在JavaScript中捕获浏览器的“缩放”事件


162

用户更改页面缩放时,是否可以使用JavaScript检测?我只是想捕获一个“缩放”事件并对其进行响应(类似于window.onresize事件)。

谢谢。


13
我相信,在页面缩放时,较新的浏览器会触发onresize事件。
epascarello

1
我有一个类似的问题,但我不仅想知道何时更改缩放,还想知道页面加载时缩放的值。
Nosredna,2009年

3
真的不是重复的。这里的问题是关于捕获事件,而不是确定缩放级别。
阿萨夫·拉维

5
@epascarello-是的,但这不会使我的评论无效
HorusKol 2012年

7
我想确认一下在最新的浏览器中是否发生“大小调整”。到目前为止,我看到新设置的Chrome(33),FF(28),IE(在第9模式下为11和11)在放大或缩小时都可以正确触发该事件。
Brock

Answers:


77

无法主动检测是否有变焦。我在这里找到了一个很好的条目,介绍了如何尝试实现它。

我发现了两种检测缩放级别的方法。检测缩放级别变化的一种方法取决于不缩放百分比值的事实。百分比值是相对于视口宽度的,因此不受页面缩放的影响。如果您插入两个元素,一个元素的位置以百分比表示,另一个元素的位置以像素为单位,则在缩放页面时它们将分开。找到两个元素的位置之间的比率,即可得到缩放级别。参见测试案例。 http://web.archive.org/web/20080723161031/http://novemberborn.net/javascript/page-zoom-ff3

您也可以使用以上文章中的工具进行操作。问题是您正在或多或少地对页面是否已缩放进行有根据的猜测。在某些浏览器中,这将比其他浏览器更好。

如果他们在缩放时加载了页面,则无法判断页面是否已缩放。


1
可以在主体的onload处理程序中检查size参数。奇怪的是,在调试IE8 vs. 9时,似乎正文的onresize处理函数是在IE8中传递文档的,而IE9则是传递窗口的,Chrome也是如此。
沃尔特·K

如果将两个元素放置在完全相同的位置,并且页面在缩放时加载,那么两个元素之间不会有位移吗?这不能告诉您页面是否已经缩放吗?
vijayant

document.body.offsetWidth
Samy Bencherif

使用这样的方法在用户调整窗口大小时也会触发,那么为什么不只使用resize事件侦听器呢?在这种情况下,这也是可行的解决方案。
hewiefreeman

12

我正在使用这段JavaScript对Zoom“事件”做出反应。
它轮询窗口宽度。(正如该页面上建议的那样(Ian Elliott链接到此页面):http : //novemberborn.net/javascript/page-zoom-ff3 [archive]

已在Chrome,Firefox 3.6和Opera(而非IE)上进行测试。

问候,马格努斯

var zoomListeners = [];

(function(){
  // Poll the pixel width of the window; invoke zoom listeners
  // if the width has been changed.
  var lastWidth = 0;
  function pollZoomFireEvent() {
    var widthNow = jQuery(window).width();
    if (lastWidth == widthNow) return;
    lastWidth = widthNow;
    // Length changed, user must have zoomed, invoke listeners.
    for (i = zoomListeners.length - 1; i >= 0; --i) {
      zoomListeners[i]();
    }
  }
  setInterval(pollZoomFireEvent, 100);
})();

8
调整窗口大小的误报怎么办?
gcb 2010年

5
但是,当您还实现onresize处理程序时,可以过滤掉这些情况。因此,我要说的是解决方案的基础。
Stijn de Witt 2012年

@StijndeWitt在阅读本文之后,我开始理解建议的路径,现在我正在研究一种过滤掉大小调整事件的解决方案,尤其是在移动设备上。任何人?
lowtechsun

也许您可以使用间隙值来区分大小和缩放?我的意思是缩放将立即将窗口宽度更改> x像素。
塞巴斯蒂安

1
误报是个问题,是的。通过检查宽高比是否保持不变,是否可以消除99.99%的所有误报?让脚本记住上一个比率并计算新比率并检查是否相同。结合宽度有所不同,您应该有一个良好的基础
Biepbot Von Stirling

11

好消息 大家有些人!更改缩放比例时,较新的浏览器将触发窗口调整大小事件。


适用于Android的Chrome和Firefox不会触发缩放事件。
lowtechsun

5
如果您不希望缩放触发大小调整事件,则这不是好消息。
Reahreic '17

12
更好的消息是与缩放事件不同的实际缩放事件。
文森特

3
都是真的。编辑。

是否可以通过某种方式设置变焦?
老男孩

9

让我们定义px_ratio如下:

px比率=物理像素与css px的比率。

如果任何一个缩放页面,则视口pxes(像素与pixel不同)减小并且应适合屏幕,因此比例(物理像素/ CSS_px)必须变大。

但是在窗口“调整大小”中,屏幕尺寸会减小,并且会降低像素数。因此该比例将保持不变。

缩放:触发windows.resize事件->并更改px_ratio

调整大小:触发windows.resize事件->不变px_ratio

//for zoom detection
px_ratio = window.devicePixelRatio || window.screen.availWidth / document.documentElement.clientWidth;

$(window).resize(function(){isZooming();});

function isZooming(){
    var newPx_ratio = window.devicePixelRatio || window.screen.availWidth / document.documentElement.clientWidth;
    if(newPx_ratio != px_ratio){
        px_ratio = newPx_ratio;
        console.log("zooming");
        return true;
    }else{
        console.log("just resizing");
        return false;
    }
}

关键是CSS PX和Physical Pixel之间的区别。

https://gist.github.com/abilogos/66aba96bb0fb27ab3ed4a13245817d1e


这应该是IMO接受的答案。到目前为止工作正常,谢谢!如果有人感兴趣,请将其包装到自定义事件gist.github.com/souporserious/b44ea5d04c38c2e7ff32cd1912a17cd0
可怕的

6

这对我有用:

        var deviceXDPI = screen.deviceXDPI;
        setInterval(function(){
            if(screen.deviceXDPI != deviceXDPI){
                deviceXDPI = screen.deviceXDPI;
                ... there was a resize ...
            }
        }, 500);

仅在IE8上需要。所有其他浏览器自然会生成一个调整大小事件。


3

有一个内置的漂亮插件yonran可以进行检测。这是他先前在StackOverflow 上回答的问题。它适用于大多数浏览器。应用程序很简单:

window.onresize = function onresize() {
  var r = DetectZoom.ratios();
  zoomLevel.innerHTML =
    "Zoom level: " + r.zoom +
    (r.zoom !== r.devicePxPerCssPx
        ? "; device to CSS pixel ratio: " + r.devicePxPerCssPx
        : "");
}

演示版


在Android 4.4.2的Firefox上不起作用。同样在FF移动版中,选中Always enable zoom“辅助功能”选项中的按钮。该演示不会对更改做出反应。
lowtechsun

2

我想建议对以前的解决方案进行改进,以跟踪窗口宽度的变化。您可以使用现有的javascript事件系统并在宽度更改时触发您自己的事件,然后将事件处理程序绑定到该事件,而不是保留自己的事件侦听器数组。

$(window).bind('myZoomEvent', function() { ... });

function pollZoomFireEvent() 
{ 

    if ( ... width changed ... ) {
        $(window).trigger('myZoomEvent');
    }
}

油门/反跳可以帮助降低处理程序的呼叫率。


1
油门/去抖仅在轮询是由其他一些事件(例如鼠标移动或键入)触发时才有用。
FuzzyTew11年

1

您还可以通过注入至少包含一个不可破坏空间(可能是隐藏的)的div并定期检查其高度来获取文本调整大小事件和缩放系数。如果高度发生变化,则文字大小也发生了变化((您知道多少-顺便说一句,如果窗口在全页模式下缩放,这也会触发),并且您仍然会获得正确的缩放系数,而高度/高度比例)。


1
<script>
var zoomv = function() {
  if(topRightqs.style.width=='200px){
  alert ("zoom");
  }
};
zoomv();
</script>

1

在iOS 10上,可以向事件添加事件侦听器,touchmove并检测页面是否被当前事件放大。

var prevZoomFactorX;
var prevZoomFactorY;
element.addEventListener("touchmove", (ev) => {
  let zoomFactorX = document.documentElement.clientWidth / window.innerWidth;
  let zoomFactorY = document.documentElement.clientHeight / window.innerHeight;
  let pageHasZoom = !(zoomFactorX === 1 && zoomFactorY === 1);

  if(pageHasZoom) {
    // page is zoomed
    
    if(zoomFactorX !== prevZoomFactorX || zoomFactorY !== prevZoomFactorY) {
      // page is zoomed with this event
    }
  }
  prevZoomFactorX = zoomFactorX;
  prevZoomFactorY = zoomFactorY;
});


1

尽管这是一个有9年历史的问题,但问题仍然存在!

我在排除项目缩放时一直在检测调整大小,因此我编辑了代码以使其能够同时检测缩放和缩放。它在大多数情况下都有效,因此,如果大多数都足以满足您的项目要求,那么这应该会有所帮助!到目前为止,它可以检测到100%的缩放比例。唯一的问题是,如果用户发疯(即,对窗口进行大小调整)或窗口滞后,则可能会因为缩放而不是调整窗口大小而触发。

它通过检测窗口大小的变化window.outerWidthwindow.outerHeight作为窗口大小调整而工作,同时检测窗口大小的变化window.innerWidthwindow.innerHeight独立于缩放窗口(而不是缩放)来工作。

//init object to store window properties
var windowSize = {
  w: window.outerWidth,
  h: window.outerHeight,
  iw: window.innerWidth,
  ih: window.innerHeight
};

window.addEventListener("resize", function() {
  //if window resizes
  if (window.outerWidth !== windowSize.w || window.outerHeight !== windowSize.h) {
    windowSize.w = window.outerWidth; // update object with current window properties
    windowSize.h = window.outerHeight;
    windowSize.iw = window.innerWidth;
    windowSize.ih = window.innerHeight;
    console.log("you're resizing"); //output
  }
  //if the window doesn't resize but the content inside does by + or - 5%
  else if (window.innerWidth + window.innerWidth * .05 < windowSize.iw ||
    window.innerWidth - window.innerWidth * .05 > windowSize.iw) {
    console.log("you're zooming")
    windowSize.iw = window.innerWidth;
  }
}, false);

注意:我的解决方案就像KajMagnus的解决方案一样,但这对我来说效果更好。


2
我不会投反对票,因为我可以看到您有一个可行的解决方案,并且我了解您的代码能做什么,但是我不建议您使用魔术数字,例如0.05至少没有提供很好的解释。;-)例如,我知道在Chrome中,无论如何,浏览器在任何情况下都会缩放的最小量为10%,但尚不清楚其他浏览器是否如此。供您参考,始终确保您的代码已经过测试,并准备捍卫或改进它。
Nolo)

有趣的方法
老男孩

1

这是一个干净的解决方案:

// polyfill window.devicePixelRatio for IE
if(!window.devicePixelRatio){
  Object.defineProperty(window,'devicePixelRatio',{
    enumerable: true,
    configurable: true,
    get:function(){
      return screen.deviceXDPI/screen.logicalXDPI;
    }
  });
}
var oldValue=window.devicePixelRatio;
window.addEventListener('resize',function(e){
  var newValue=window.devicePixelRatio;
  if(newValue!==oldValue){
    // TODO polyfill CustomEvent for IE
    var event=new CustomEvent('devicepixelratiochange');
    event.oldValue=oldValue;
    event.newValue=newValue;
    oldValue=newValue;
    window.dispatchEvent(event);
  }
});

window.addEventListener('devicepixelratiochange',function(e){
  console.log('devicePixelRatio changed from '+e.oldValue+' to '+e.newValue);
});


这似乎是一个非常不错的解决方案,并且使用代理服务器,您甚至不需要使用拦截器破坏寡妇属性-我们是否确定当用户缩放时更新DPR是所有浏览器都应该/应该做什么?嗯..刮掉这个主意-窗口无法被代理,也许存在使用“ matchMedia”的解决方案,但是由于这是对/错的事情,所以我不确定如何测试模拟值的变化DPR ...
Jon z

0

在现代浏览器上windowresize事件可以通过将事件附加到上,然后body使用例如(.getBoundingClientRect())来读取或其他元素的值来工作。

在某些早期的浏览器中,可以在任何HTML元素上注册调整大小事件处理程序。仍然可以设置onresize属性或使用addEventListener()在任何元素上设置处理程序。但是,调整大小事件仅在窗口对象上触发(即由document.defaultView返回)。只有在window对象上注册的处理程序将接收调整大小事件

window.addEventListener("resize", getSizes, false)
        
function getSizes(){
  let body = document.body
  console.log(body.clientWidth +"px x "+ body.clientHeight + "px")
}

另一种选择ResizeObserver API

根据您的布局,您可以注意调整特定元素的大小。

这在“响应式”布局上效果很好,因为在缩放时会调整容器框的大小。

function watchBoxchange(e){
 // console.log(e[0].contentBoxSize.inlineSize+" "+e[0].contentBoxSize.blockSize)
 info.textContent = e[0].contentBoxSize.inlineSize+" * "+e[0].contentBoxSize.blockSize + "px"
}

new ResizeObserver(watchBoxchange).observe(fluid)
#fluid {
  width: 200px;
  height:100px;
  overflow: auto;
  resize: both;
  border: 3px black solid;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  font-size: 8vh
}
<div id="fluid">
   <info id="info"></info> 
</div>


请注意不要使用户手势事件中的javascript任务超载。需要重绘时,请使用requestAnimationFrame


0

根据MDN的说法,“ matchMedia”是执行此操作的正确方法https://developer.mozilla.org/zh-CN/docs/Web/API/Window/devicePixelRatio#Monitoring_screen_resolution_or_zoom_level_changes

这有点挑剔,因为每个实例一次只能观看一个MQ,因此,如果您对任何缩放级别更改需要进行一系列匹配。.但是由于浏览器负责发出事件,因此可能比轮询还具有更高的性能,您可以限制或消除回调,或将其固定到动画帧或其他东西上-这是一个看起来非常敏捷的实现,可以随意切换_throttle或如果已经依赖它。

运行代码片段并在浏览器中放大和缩小,注意标记中的更新值-我仅在Firefox中进行了测试!莱姆知道您是否发现任何问题。

const el = document.querySelector('#dppx')

if ('matchMedia' in window) {
  function observeZoom(cb, opts) {
    opts = {
      // first pass for defaults - range and granularity to capture all the zoom levels in desktop firefox
      ceiling: 3,
      floor: 0.3,
      granularity: 0.05,
      ...opts
    }
    const precision = `${opts.granularity}`.split('.')[1].length

    let val = opts.floor
    const vals = []
    while (val <= opts.ceiling) {
      vals.push(val)
      val = parseFloat((val + opts.granularity).toFixed(precision))
    }

    // construct a number of mediamatchers and assign CB to all of them
    const mqls = vals.map(v => matchMedia(`(min-resolution: ${v}dppx)`))

    // poor person's throttle
    const throttle = 3
    let last = performance.now()
    mqls.forEach(mql => mql.addListener(function() {
      console.debug(this, arguments)
      const now = performance.now()
      if (now - last > throttle) {
        cb()
        last = now
      }
    }))
  }

  observeZoom(function() {
    el.innerText = window.devicePixelRatio
  })
} else {
  el.innerText = 'unable to observe zoom level changes, matchMedia is not supported'
}
<div id='dppx'>--</div>


-4

我正在回复3岁的链接,但我想这是一个更可接受的答案,

创建.css文件为

@media screen and (max-width: 1000px) 
{
       // things you want to trigger when the screen is zoomed
}

例如:-

@media screen and (max-width: 1000px) 
{
    .classname
    {
          font-size:10px;
    }
}

上面的代码将屏幕缩放到大约125%时的字体大小为“ 10px”。您可以通过更改“ 1000px”的值来检查不同的缩放级别。


max-width和缩放比例之间有什么关系?
seebiscuit

这段代码将在每个<1000px屏幕上执行,并且与缩放无关
Artur Stary

@ArturStary无法检测浏览器是否已缩放,但是有许多解决方法,其中之一就是我在回答中提到的方法。此外,我确实说过,您可以更改
1000px
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.