[javascript] Catch browser's "zoom" event in JavaScript

Is it possible to detect, using JavaScript, when the user changes the zoom in a page? I simply want to catch a "zoom" event and respond to it (similar to window.onresize event).

Thanks.

This question is related to javascript events zooming

The answer is


Although this is a 9 yr old question, the problem persists!

I have been detecting resize while excluding zoom in a project, so I edited my code to make it work to detect both resize and zoom exclusive from one another. It works most of the time, so if most is good enough for your project, then this should be helpful! It detects zooming 100% of the time in what I've tested so far. The only issue is that if the user gets crazy (ie. spastically resizing the window) or the window lags it may fire as a zoom instead of a window resize.

It works by detecting a change in window.outerWidth or window.outerHeight as window resizing while detecting a change in window.innerWidth or window.innerHeight independent from window resizing as a zoom.

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

Note: My solution is like KajMagnus's, but this has worked better for me.


There is a nifty plugin built from yonran that can do the detection. Here is his previously answered question on StackOverflow. It works for most of the browsers. Application is as simple as this:

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
        : "");
}

Demo


Good news everyone some people! Newer browsers will trigger a window resize event when the zoom is changed.


You can also get the text resize events, and the zoom factor by injecting a div containing at least a non-breakable space (possibly, hidden), and regularly checking its height. If the height changes, the text size has changed, (and you know how much - this also fires, incidentally, if the window gets zoomed in full-page mode, and you still will get the correct zoom factor, with the same height / height ratio).


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

Here is a native way (major frameworks cannot zoom in Chrome, because they dont supports passive event behaviour)


//For Google Chrome
document.addEventListener("mousewheel", event => {
  console.log(`wheel`);
  if(event.ctrlKey == true)
  {
    event.preventDefault();
    if(event.deltaY > 0) {
      console.log('Down');
    }else {
      console.log('Up');
    }
  }
}, { passive: false });

// For Mozilla Firefox
document.addEventListener("DOMMouseScroll", event => {
  console.log(`wheel`);
  if(event.ctrlKey == true)
  {
    event.preventDefault();
    if(event.detail > 0) {
      console.log('Down');
    }else {
      console.log('Up');
    }
  }
}, { passive: false });


The resize event works on modern browsers by attaching the event on window, and then reading values of thebody, or other element with for example (.getBoundingClientRect()).

In some earlier browsers it was possible to register resize event handlers on any HTML element. It is still possible to set onresize attributes or use addEventListener() to set a handler on any element. However, resize events are only fired on the window object (i.e. returned by document.defaultView). Only handlers registered on the window object will receive resize events.

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

An other alternative: the ResizeObserver API

Depending your layout, you can watch for resizing on a particular element.

This works well on «responsive» layouts, because the container box get resized when zooming.

_x000D_
_x000D_
function watchBoxchange(e){_x000D_
 // console.log(e[0].contentBoxSize.inlineSize+" "+e[0].contentBoxSize.blockSize)_x000D_
 info.textContent = e[0].contentBoxSize.inlineSize+" * "+e[0].contentBoxSize.blockSize + "px"_x000D_
}_x000D_
_x000D_
new ResizeObserver(watchBoxchange).observe(fluid)
_x000D_
#fluid {_x000D_
  width: 200px;_x000D_
  height:100px;_x000D_
  overflow: auto;_x000D_
  resize: both;_x000D_
  border: 3px black solid;_x000D_
  display: flex;_x000D_
  flex-direction: column;_x000D_
  justify-content: center;_x000D_
  align-items: center;_x000D_
  font-size: 8vh_x000D_
}
_x000D_
<div id="fluid">_x000D_
   <info id="info"></info> _x000D_
</div>
_x000D_
_x000D_
_x000D_


Be careful to not overload javascript tasks from user gestures events. Use requestAnimationFrame whenever you needs redraws.


Here is a clean solution:

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


I'am replying to a 3 year old link but I guess here's a more acceptable answer,

Create .css file as,

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

EG:-

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

The above code makes the size of the font '10px' when the screen is zoomed to approximately 125%. You can check for different zoom level by changing the value of '1000px'.


According to MDN, "matchMedia" is the proper way to do this https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#Monitoring_screen_resolution_or_zoom_level_changes

it's a bit finicky because each instance can only watch one MQ at a time, so if you're interested in any zoom level change you need to make a bunch of matchers.. but since the browser is in charge to emitting the events it's probably still more performant than polling, and you could throttle or debounce the callback or pin it to an animation frame or something - here's an implementation that seems pretty snappy, feel free to swap in _throttle or whatever if you're already depending on that.

Run the code snippet and zoom in and out in your browser, note the updated value in the markup - I only tested this in Firefox! lemme know if you see any issues.

_x000D_
_x000D_
const el = document.querySelector('#dppx')_x000D_
_x000D_
if ('matchMedia' in window) {_x000D_
  function observeZoom(cb, opts) {_x000D_
    opts = {_x000D_
      // first pass for defaults - range and granularity to capture all the zoom levels in desktop firefox_x000D_
      ceiling: 3,_x000D_
      floor: 0.3,_x000D_
      granularity: 0.05,_x000D_
      ...opts_x000D_
    }_x000D_
    const precision = `${opts.granularity}`.split('.')[1].length_x000D_
_x000D_
    let val = opts.floor_x000D_
    const vals = []_x000D_
    while (val <= opts.ceiling) {_x000D_
      vals.push(val)_x000D_
      val = parseFloat((val + opts.granularity).toFixed(precision))_x000D_
    }_x000D_
_x000D_
    // construct a number of mediamatchers and assign CB to all of them_x000D_
    const mqls = vals.map(v => matchMedia(`(min-resolution: ${v}dppx)`))_x000D_
_x000D_
    // poor person's throttle_x000D_
    const throttle = 3_x000D_
    let last = performance.now()_x000D_
    mqls.forEach(mql => mql.addListener(function() {_x000D_
      console.debug(this, arguments)_x000D_
      const now = performance.now()_x000D_
      if (now - last > throttle) {_x000D_
        cb()_x000D_
        last = now_x000D_
      }_x000D_
    }))_x000D_
  }_x000D_
_x000D_
  observeZoom(function() {_x000D_
    el.innerText = window.devicePixelRatio_x000D_
  })_x000D_
} else {_x000D_
  el.innerText = 'unable to observe zoom level changes, matchMedia is not supported'_x000D_
}
_x000D_
<div id='dppx'>--</div>
_x000D_
_x000D_
_x000D_


On iOS 10 it is possible to add an event listener to the touchmove event and to detect, if the page is zoomed with the current event.

_x000D_
_x000D_
var prevZoomFactorX;_x000D_
var prevZoomFactorY;_x000D_
element.addEventListener("touchmove", (ev) => {_x000D_
  let zoomFactorX = document.documentElement.clientWidth / window.innerWidth;_x000D_
  let zoomFactorY = document.documentElement.clientHeight / window.innerHeight;_x000D_
  let pageHasZoom = !(zoomFactorX === 1 && zoomFactorY === 1);_x000D_
_x000D_
  if(pageHasZoom) {_x000D_
    // page is zoomed_x000D_
    _x000D_
    if(zoomFactorX !== prevZoomFactorX || zoomFactorY !== prevZoomFactorY) {_x000D_
      // page is zoomed with this event_x000D_
    }_x000D_
  }_x000D_
  prevZoomFactorX = zoomFactorX;_x000D_
  prevZoomFactorY = zoomFactorY;_x000D_
});
_x000D_
_x000D_
_x000D_


I'm using this piece of JavaScript to react to Zoom "events".
It polls the window width. (As somewhat suggested on this page (which Ian Elliott linked to): http://novemberborn.net/javascript/page-zoom-ff3 [archive])

Tested with Chrome, Firefox 3.6 and Opera, not IE.

Regards, Magnus

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);
})();

I'd like to suggest an improvement to previous solution with tracking changes to window width. Instead of keeping your own array of event listeners you can use existing javascript event system and trigger your own event upon width change, and bind event handlers to it.

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

function pollZoomFireEvent() 
{ 

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

Throttle/debounce can help with reducing the rate of calls of your handler.


Lets define px_ratio as below:

px ratio = ratio of physical pixel to css px.

if any one zoom The Page, the viewport pxes (px is different from pixel ) reduces and should be fit to The screen so the ratio (physical pixel / CSS_px ) must get bigger.

but in window Resizing, screen size reduces as well as pxes. so the ratio will maintain.

zooming: trigger windows.resize event --> and change px_ratio

but

resizing: trigger windows.resize event --> doesn’t change 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;
    }
}

The key point is difference between CSS PX and Physical Pixel.

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


This works for me:

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

It's only needed on IE8. All the other browsers naturally generate a resize event.


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to events

onKeyDown event not working on divs in React Detect click outside Angular component Angular 2 Hover event Global Events in Angular How to fire an event when v-model changes? Passing string parameter in JavaScript function Capture close event on Bootstrap Modal AngularJs event to call after content is loaded Remove All Event Listeners of Specific Type Jquery .on('scroll') not firing the event while scrolling

Examples related to zooming

IntelliJ how to zoom in / out Disable double-tap "zoom" option in browser on touch devices How to implement zoom effect for image view in android? android pinch zoom enable/disable zoom in Android WebView How can I zoom an HTML element in Firefox and Opera? Disable Auto Zoom in Input "Text" tag - Safari on iPhone How can I get zoom functionality for images? How to detect page zoom level in all modern browsers? Changing the browser zoom level