330
  1. How can I detect the page zoom level in all modern browsers? While this thread tells how to do it in IE7 and IE8, I can't find a good cross-browser solution.

  2. Firefox stores the page zoom level for future access. On the first page load, would I be able to get the zoom level? Somewhere I read it works when a zoom change occurs after the page is loaded.

  3. Is there a way to trap the 'zoom' event?

I need this because some of my calculations are pixel-based and they may fluctuate when zoomed.


Modified sample given by @tfl

This page alerts different height values when zoomed. [jsFiddle]

<html>
    <head>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js" type="text/javascript"/></script>
    </head>
    <body>
        <div id="xy" style="border:1px solid #f00; width:100px;">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque sollicitudin tortor in lacus tincidunt volutpat. Integer dignissim imperdiet mollis. Suspendisse quis tortor velit, placerat tempor neque. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent bibendum auctor lorem vitae tempor. Nullam condimentum aliquam elementum. Nullam egestas gravida elementum. Maecenas mattis molestie nisl sit amet vehicula. Donec semper tristique blandit. Vestibulum adipiscing placerat mollis.</div>
        <button onclick="alert($('#xy').height());">Show</button>
    </body>
</html>
Vega
  • 23,736
  • 20
  • 78
  • 88
understack
  • 10,311
  • 23
  • 72
  • 97

27 Answers27

286

Now it's an even bigger mess than it was when this question was first asked. From reading all the responses and blog posts I could find, here's a summary. I also set up this page to test all these methods of measuring the zoom level.

Edit (2011-12-12): I've added a project that can be cloned: https://github.com/tombigel/detect-zoom

  • IE8: screen.deviceXDPI / screen.logicalXDPI (or, for the zoom level relative to default zoom, screen.systemXDPI / screen.logicalXDPI)
  • IE7: var body = document.body,r = body.getBoundingClientRect(); return (r.left-r.right)/body.offsetWidth; (thanks to this example or this answer)
  • FF3.5 ONLY: screen.width / media query screen width (see below) (takes advantage of the fact that screen.width uses device pixels but MQ width uses CSS pixels--thanks to Quirksmode widths)
  • FF3.6: no known method
  • FF4+: media queries binary search (see below)
  • WebKit: https://www.chromestatus.com/feature/5737866978131968 (thanks to Teo in the comments)
  • WebKit: measure the preferred size of a div with -webkit-text-size-adjust:none.
  • WebKit: (broken since r72591) document.width / jQuery(document).width() (thanks to Dirk van Oosterbosch above). To get ratio in terms of device pixels (instead of relative to default zoom), multiply by window.devicePixelRatio.
  • Old WebKit? (unverified): parseInt(getComputedStyle(document.documentElement,null).width) / document.documentElement.clientWidth (from this answer)
  • Opera: document.documentElement.offsetWidth / width of a position:fixed; width:100% div. from here (Quirksmode's widths table says it's a bug; innerWidth should be CSS px). We use the position:fixed element to get the width of the viewport including the space where the scrollbars are; document.documentElement.clientWidth excludes this width. This is broken since sometime in 2011; I know no way to get the zoom level in Opera anymore.
  • Other: Flash solution from Sebastian
  • Unreliable: listen to mouse events and measure change in screenX / change in clientX

Here's a binary search for Firefox 4, since I don't know of any variable where it is exposed:

<style id=binarysearch></style>
<div id=dummyElement>Dummy element to test media queries.</div>
<script>
var mediaQueryMatches = function(property, r) {
  var style = document.getElementById('binarysearch');
  var dummyElement = document.getElementById('dummyElement');
  style.sheet.insertRule('@media (' + property + ':' + r +
                         ') {#dummyElement ' +
                         '{text-decoration: underline} }', 0);
  var matched = getComputedStyle(dummyElement, null).textDecoration
      == 'underline';
  style.sheet.deleteRule(0);
  return matched;
};
var mediaQueryBinarySearch = function(
    property, unit, a, b, maxIter, epsilon) {
  var mid = (a + b)/2;
  if (maxIter == 0 || b - a < epsilon) return mid;
  if (mediaQueryMatches(property, mid + unit)) {
    return mediaQueryBinarySearch(
        property, unit, mid, b, maxIter-1, epsilon);
  } else {
    return mediaQueryBinarySearch(
        property, unit, a, mid, maxIter-1, epsilon);
  }
};
var mozDevicePixelRatio = mediaQueryBinarySearch(
    'min--moz-device-pixel-ratio', '', a, b, maxIter, epsilon);
var ff35DevicePixelRatio = screen.width / mediaQueryBinarySearch(
    'min-device-width', 'px', 0, 6000, 25, .0001);
</script>
Claude
  • 6,353
  • 3
  • 31
  • 48
yonran
  • 15,964
  • 7
  • 60
  • 81
  • 1
    Very nice work, although this does't work for me in IE 8.0.7601.17514 (latest). Any chance to wrap all this up in a single function getZoom() that works across all browsers? Perhaps also release as a jQuery plugin? Nice work again. – ripper234 Oct 09 '11 at 09:45
  • 1
    @yonran great plugin!, But it does not work in IE9 it should be `zoom: screen.deviceXDPI / screen.logicalXDPI,` instead of `zoom: screen.systemXDPI / screen.logicalXDPI,` – Daniel Jun 25 '12 at 06:02
  • @yonran Do you have a reason to prefer inserting CSS rules over using the [`window.matchMedia`](https://developer.mozilla.org/en-US/docs/Web/API/window.matchMedia) method? – Rob W Aug 30 '13 at 19:35
  • 1
    @RobW, when I first wrote this for Firefox 4, Firefox didn’t have `matchMedia`. Paul Irish also wrote a [similar matchMedia polyfill](https://github.com/paulirish/matchMedia.js/) that is part of [Modernizr](http://modernizr.com/). – yonran Aug 30 '13 at 20:06
  • 1
    window.outerWidth / window.innerWidth * 100 works for the recent Chrome version – Dmitry S. Dec 24 '13 at 17:08
  • It is worth noting that since April 2013, Chrome has forked WebKit into Blink. So nowadays things that apply to WebKit might not apply to Chrome. http://blog.chromium.org/2013/04/blink-rendering-engine-for-chromium.html – Denilson Sá Maia May 09 '14 at 17:11
  • `document.width` is `undefined` on Chrome 37.0.2062.120 – c00000fd Sep 18 '14 at 06:46
  • 1
    2017 and still doesn't seem to have an answer. I did notice, however, that FF shows the original size of the element in the inspector regardless of zoom. I would hope this is exposed somewhere, but so far I haven't found it. – Matthew Sanders Mar 20 '17 at 21:26
  • 1
    So how do we get browser makers to add it as a standard API method? I don't think they are scouring the SO forums for questions developers have. Would it be a good idea to have an up vote button for "Adding this as an API to language"? Then manufacturers *could* scour the forums and see votes on issues they want prioritized? – 1.21 gigawatts Apr 11 '17 at 14:21
  • 7
    Good news, everyone! They finaly did it! Vieport API! https://www.chromestatus.com/feature/5737866978131968 I test it, great stuff! – Teo Oct 03 '17 at 13:57
  • 1
    I'm not opposed to this being difficult, just like it's difficult to determine if a user has assistive technology. There's plenty of room here for active discrimination against assistive technology users, just like we try to tell people to switch browsers we don't want to support. I'd argue that if you need to check for user zoom, then you're not frontending right in the first place. As @Max mentioned, it's 2018. – Jason T Featheringham Mar 07 '18 at 05:01
  • 6
    The Viewport API only works for pinch-zoom; if you zoom on desktop it says scale is 1. @Jason T Featheringham there are reasons other than "discrimination" to want to know the zoom level. Zoom is set across all pages for a domain, but you might want to handle it differently in a game page or an extension popup than you do in a help page. – Pudica Mar 27 '18 at 12:52
  • @JasonTFeatheringham Also depending on how sites are previous setup, new accessibility requirement will alter current behaviour and there may be a need to detect zoom so that the site can adjust accordingly. You can argue that the project should be redone or this should of been done in the first place but that's simply not how the real world works when you have clients and budgets – Huangism Jul 10 '20 at 16:22
  • You may have clients and budgets, and there may be other needs, but that does not negate the issue. To @Pudica's comment: If the user has zoomed, that means they cannot accurately see your content, and therefore it should zoom. Your argument reminds me a lot of scroll-jacking, which is also quite outdated (with things like IntersectionObserver). – Jason T Featheringham Jul 16 '20 at 07:20
69

You can try

var browserZoomLevel = Math.round(window.devicePixelRatio * 100);

This will give you browser zoom percentage level on non-retina displays. For high DPI/retina displays, it would yield different values (e.g., 200 for Chrome and Safari, 140 for Firefox).

To catch zoom event you can use

$(window).resize(function() { 
// your code 
});
Clokman
  • 149
  • 1
  • 8
user1080381
  • 1,252
  • 1
  • 13
  • 20
  • 1
    Works perfect, also on mobile devices. It is also quite interesting to see what mobile devices have what `devicePixelRatio`. This also greatly helped me switching a `fixed` element to `absolute`ly positioned element when the zoom event occurs, or when the inital value of `devicePixelRatio` changes. Perfect! Thank you!! – lowtechsun Jan 24 '17 at 12:56
  • 15
    Doesn't work as expected: It returns 200 in Chrome on MacBook with retina when browser not zoomed. – Terite Mar 22 '17 at 09:51
  • 21
    Browsers with support for high DPI screens will not give the expected outcome when using such display, neither will Safari regardless of display. – Fredrik C Apr 25 '17 at 12:15
  • Just for anyone that cares, on IE this only works on IE11 (it will return NaN on IE10 or below) – scunliffe Apr 16 '19 at 19:37
  • 3
    `Math.round(window.devicePixelRatio * 100)` works on Chrome, IE, Edge, and Firefox. Safari on iMac always returns 200. – Super Jade Oct 04 '19 at 17:57
  • Tested on Chrome 78 on Mac and doesn't work... It returned 350 once, then always 200 regardless of zoom level :( – collimarco Nov 26 '19 at 23:40
  • This doesn't work on Chrome on Retina displays, as the default value is not 1, but 2. Different screens with different pixel densities should deliver different values. – Ignacio Segura Feb 12 '20 at 11:43
  • On windows it unfortunately multiplies both the displays and browsers zoom level – Gerrit Sedlaczek Mar 20 '20 at 08:05
  • Does not work unfortunatelly. I get 120 when i zoom 80 – Black May 26 '21 at 14:53
48

For me, for Chrome/Webkit, document.width / jQuery(document).width() did not work. When I made my window small and zoomed into my site such that horizontal scrollbars appeared, document.width / jQuery(document).width() did not equal 1 at the default zoom. This is because document.width includes part of the document outside the viewport.

Using window.innerWidth and window.outerWidth worked. For some reason in Chrome, outerWidth is measured in screen pixels and innerWidth is measured in css pixels.

var screenCssPixelRatio = (window.outerWidth - 8) / window.innerWidth;
if (screenCssPixelRatio >= .46 && screenCssPixelRatio <= .54) {
  zoomLevel = "-4";
} else if (screenCssPixelRatio <= .64) {
  zoomLevel = "-3";
} else if (screenCssPixelRatio <= .76) {
  zoomLevel = "-2";
} else if (screenCssPixelRatio <= .92) {
  zoomLevel = "-1";
} else if (screenCssPixelRatio <= 1.10) {
  zoomLevel = "0";
} else if (screenCssPixelRatio <= 1.32) {
  zoomLevel = "1";
} else if (screenCssPixelRatio <= 1.58) {
  zoomLevel = "2";
} else if (screenCssPixelRatio <= 1.90) {
  zoomLevel = "3";
} else if (screenCssPixelRatio <= 2.28) {
  zoomLevel = "4";
} else if (screenCssPixelRatio <= 2.70) {
  zoomLevel = "5";
} else {
  zoomLevel = "unknown";
}
RamenChef
  • 5,533
  • 11
  • 28
  • 39
user800583
  • 497
  • 4
  • 2
  • 1
    Very nice. And if you only need to know whether it's zoomed or not in Chrome: `isZoomed = (screenCssPixelRatio < .98 || screenCssPixelRatio > 1.02)` – Brent Faust Dec 30 '11 at 02:14
  • 1
    Well, window.outerWidth is changed with the zoom too. Also, not on every OS the window border width is 8 pixels (even on same OS the design can vary). However I would suggest to substract 16, not 8, since you have the window borders twice. Also, some browser have a border on their actual rendering window (like FF) and some not (Safari) - but even this depends on which OS you use the browser (e. g. Safari has a border on Windows). Backing up the initial innerWidth (e. g. on page load) and use it to compare works better but only if initional zoom was 100%... – StanE Dec 04 '14 at 19:56
  • 1
    Outputs 0 no matter what for me (2017, feb). – Tiberiu-Ionuț Stan Feb 21 '17 at 14:06
  • 1
    `switch` statement may be better than many if else statements. – Edric Feb 03 '18 at 06:15
  • It doesn't work: just tested on Chrome on Mac and it always returns the same ratio, regardless of zoom level – collimarco Nov 27 '19 at 16:00
  • Unfortunately, it doesn't work correctly when the page is inside an iframe that's not 100% of the parent page – Finesse Jan 19 '21 at 02:37
  • This is working in Chrome and Edge however both browsers include the debug (F12) window in the outerWidth so if this is open your results will vary wildly. – Paul Apr 26 '21 at 14:52
15

My coworker and I used the script from https://github.com/tombigel/detect-zoom. In addition, we also dynamically created a svg element and check its currentScale property. It works great on Chrome and likely most browsers too. On FF the "zoom text only" feature has to be turned off though. SVG is supported on most browsers. At the time of this writing, tested on IE10, FF19 and Chrome28.

var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
svg.setAttribute('version', '1.1');
document.body.appendChild(svg);
var z = svg.currentScale;
... more code ...
document.body.removeChild(svg);
Jay
  • 169
  • 1
  • 3
  • 1
    This method now always report svg.currentScale = 1 in Firefox 29. Probably because they resize the entire screen figures based on zoom which is a [bug](https://bugzilla.mozilla.org/show_bug.cgi?id=1022006). IE11 seem to have the same problem on Desktop with the screen height adjusted to the viewport devicePixelRatio which is quite screwed up. – hexalys Jun 07 '14 at 03:26
12

I found this article enormously helpful. Huge thanks to yonran. I wanted to pass on some additional learning I found while implementing some of the techniques he provided. In FF6 and Chrome 9, support for media queries from JS was added, which can greatly simplify the media query approach necessary for determining zoom in FF. See the docs at MDN here. For my purposes, I only needed to detect whether the browser was zoomed in or out, I had no need for the actual zoom factor. I was able to get my answer with one line of JavaScript:

var isZoomed = window.matchMedia('(max--moz-device-pixel-ratio:0.99), (min--moz-device-pixel-ratio:1.01)').matches;

Combining this with the IE8+ and Webkit solutions, which were also single lines, I was able to detect zoom on the vast majority of browsers hitting our app with only a few lines of code.

brianh
  • 121
  • 1
  • 3
  • 4
    Could you please provide a code how to detect actual zoom using media query? – TN. Nov 08 '11 at 00:07
  • Try using just "(width: px) and (height: px)" where and are window.innerWidth and window.innerHeight, respectively. It works even for very tiny amounts of zoom. Works in Safari too. – max Mar 23 '15 at 22:46
  • @max Can you provide a JSFIddle or sample code of how this looks put together please? – lowtechsun Jan 23 '17 at 15:25
  • Always reports true on retina devices such as macbook pro. – Matthew Sanders Mar 20 '17 at 21:28
  • https://codepen.io/anon/pen/LgrGjJ shows a binary search with media queries, but this is the same as querying `devicePixelRatio`: it takes into account display scaling. – ZachB Oct 19 '18 at 23:47
9
zoom = ( window.outerWidth - 10 ) / window.innerWidth

That's all you need.

Alex von Thorn
  • 155
  • 1
  • 4
7

I have a solution for this as of Jan 2016. Tested working in Chrome, Firefox and MS Edge browsers.

The principle is as follows. Collect 2 MouseEvent points that are far apart. Each mouse event comes with screen and document coordinates. Measure the distance between the 2 points in both coordinate systems. Although there are variable fixed offsets between the coordinate systems due to the browser furniture, the distance between the points should be identical if the page is not zoomed. The reason for specifying "far apart" (I put this as 12 pixels) is so that small zoom changes (e.g. 90% or 110%) are detectable.

Reference: https://developer.mozilla.org/en/docs/Web/Events/mousemove

Steps:

  1. Add a mouse move listener

    window.addEventListener("mousemove", function(event) {
        // handle event
    });
    
  2. Capture 4 measurements from mouse events:

    event.clientX, event.clientY, event.screenX, event.screenY
    
  3. Measure the distance d_c between the 2 points in the client system

  4. Measure the distance d_s between the 2 points in the screen system

  5. If d_c != d_s then zoom is applied. The difference between the two tells you the amount of zoom.

N.B. Only do the distance calculations rarely, e.g. when you can sample a new mouse event that's far from the previous one.

Limitations: Assumes user will move the mouse at least a little, and zoom is unknowable until this time.

Terite
  • 977
  • 11
  • 23
user1191311
  • 85
  • 1
  • 1
  • 1
    I created a fiddle: https://jsfiddle.net/Terite/9b6ko854/ with "far apart" meant as 100 pixels. Unfortunately it works unstable on Firefox (52) on MacBook with retina display. Also should be noted that Window 7 interface zoom 125% is detected in Chrome, Firefox and IE11 (in zoom 125% which is default then) as a browser zoom. – Terite Mar 22 '17 at 14:18
  • Your fiddle works for me, tested in Linux with Firefox and Chrome :) – user1191311 Mar 24 '17 at 02:32
  • Retina displays add another level of difficulty because they report the pixel sizes incorrectly, among other things. – user1191311 Mar 24 '17 at 02:33
4

What i came up with is :

1) Make a position:fixed <div> with width:100% (id=zoomdiv)

2) when the page loads :

zoomlevel=$("#zoomdiv").width()*1.0 / screen.availWidth

And it worked for me for ctrl+ and ctrl- zooms.

or i can add the line to a $(window).onresize() event to get the active zoom level


Code:

<script>
    var zoom=$("#zoomdiv").width()*1.0 / screen.availWidth;

    $(window).resize(function(){
        zoom=$("#zoomdiv").width()*1.0 / screen.availWidth;
        alert(zoom);    
    });
</script>
<body>
    <div id=zoomdiv style="width:100%;position:fixed;"></div>
</body>

P.S. : this is my first post, pardon any mistakes

Maxim Kolesnikov
  • 4,845
  • 5
  • 35
  • 64
  • 3
    Unfortunately, this will only work if the user has the browser maximized (`screen.availWidth` reports the width of the screen in screen pixels, not the browser window). – Bailey Parker Jun 11 '15 at 21:09
4

Basically, we have:

  • window.devicePixelRatio which takes into account both browser-level zoom* as well as system zoom/pixel density.
    * — on Mac/Safari zoom level is not taken into account
  • media queries
  • vw/vh CSS units
  • resize event, which is triggered upon zoom level change, cause effective size of the window changes

that should be enough for normal UX. If you need to detect zoom level that might be a sign of bad UI design.

Pitch-zoom is harder to track and is not considered currently.

kirilloid
  • 12,843
  • 5
  • 36
  • 50
  • 1
    window.devicePixelRatio is a good answer that works in the latest version of the major browsers - Chrome, Safari, FF, Edge, IE – DShultz Oct 31 '18 at 19:58
  • @kirilloid did you find anything that could be used to reliably find the "zoom level" in Safari? – onassar May 09 '19 at 16:44
4

You can use the Visual Viewport API:

window.visualViewport.scale;

It is standard and works both on desktop and mobile: browser support.

collimarco
  • 29,854
  • 31
  • 89
  • 120
3

This has worked great for me in webkit-based browsers (Chrome, Safari):

function isZoomed() {
    var width, mediaQuery;

    width = document.body.clientWidth;
    mediaQuery = '(max-width: ' + width + 'px) and (min-width: ' + width + 'px)';

    return !window.matchMedia(mediaQuery).matches;
}

Doesn't seem to work in Firefox though.

This also works in WebKit:

var zoomLevel = document.width / document.body.clientWidth;
Timo Tijhof
  • 9,597
  • 6
  • 31
  • 45
rudolfrck
  • 39
  • 2
3

In Internet Explorer 7, 8 & 9, this works:

function getZoom() {
    var screen;

    screen = document.frames.screen;
    return ((screen.deviceXDPI / screen.systemXDPI) * 100 + 0.9).toFixed();
}

The "+0.9" is added to prevent rounding errors (otherwise, you would get 104% and 109% when the browser zoom is set to 105% and 110% respectively).

In IE6 zoom doesn't exists, so it is unnecessary to check the zoom.

Julien Kronegg
  • 4,282
  • 42
  • 53
pench
  • 41
  • 2
1

On mobile devices (with Chrome for Android or Opera Mobile) you can detect zoom by window.visualViewport.scale. https://developer.mozilla.org/en-US/docs/Web/API/Visual_Viewport_API

Detect on Safari: document.documentElement.clientWidth / window.innerWidth (return 1 if no zooming on device).

JIm
  • 79
  • 1
  • 3
0

This is for Chrome, in the wake of user800583 answer ...

I spent a few hours on this problem and have not found a better approach, but :

  • There are 16 'zoomLevel' and not 10
  • When Chrome is fullscreen/maximized the ratio is window.outerWidth/window.innerWidth, and when it is not, the ratio seems to be (window.outerWidth-16)/window.innerWidth, however the 1st case can be approached by the 2nd one.

So I came to the following ...

But this approach has limitations : for example if you play the accordion with the application window (rapidly enlarge and reduce the width of the window) then you will get gaps between zoom levels although the zoom has not changed (may be outerWidth and innerWidth are not exactly updated in the same time).

var snap = function (r, snaps)
{
    var i;
    for (i=0; i < 16; i++) { if ( r < snaps[i] ) return i; }
};
var w, l, r;
w = window.outerWidth, l = window.innerWidth;
return snap((w - 16) / l,
            [ 0.29, 0.42, 0.58, 0.71, 0.83, 0.95, 1.05, 1.18, 1.38, 1.63, 1.88, 2.25, 2.75, 3.5, 4.5, 100 ],
);

And if you want the factor :

var snap = function (r, snaps, ratios)
{
    var i;
    for (i=0; i < 16; i++) { if ( r < snaps[i] ) return eval(ratios[i]); }
};
var w, l, r;
w = window.outerWidth, l = window.innerWidth;
return snap((w - 16) / l,
            [ 0.29, 0.42, 0.58, 0.71, 0.83, 0.95, 1.05, 1.18, 1.38, 1.63, 1.88, 2.25, 2.75, 3.5, 4.5, 100 ],
            [ 0.25, '1/3', 0.5, '2/3', 0.75, 0.9, 1, 1.1, 1.25, 1.5, 1.75, 2, 2.5, 3, 4, 5 ]
);
Community
  • 1
  • 1
jeum
  • 932
  • 2
  • 12
  • 25
  • I had problems with "window.outerWidth/window.innerWidth" giving me the wrong value too and that might of been because I was in an iframe. So what I did is I used the parent window and it gave the correct answer: window.parent.window.outerWidth/window.parent.window.innerWidth – yan bellavance Oct 25 '16 at 21:30
0

Your calculations are still based on a number of CSS pixels. They're just a different size on the screen now. That's the point of full page zoom.

What would you want to happen on a browser on a 192dpi device which therefore normally displayed four device pixels for each pixel in an image? At 50% zoom this device now displays one image pixel in one device pixel.

Neil
  • 50,855
  • 8
  • 54
  • 69
  • @Neil: how can I get 'CSS pixels' dimensions? – understack Dec 10 '09 at 11:06
  • CSS defaults to points, but you can of course specify pixels by using the px dimension modifier. As for element properties retrieved in JavaScript, these should already be in CSS pixels. So if you specify the width of a
    to be 100px, then that's what you'll get back from JavaScript, whatever the zoom level may be.
    – Neil Dec 22 '09 at 19:59
0

I have this solution for mobile only (tested with Android):

jQuery(function($){

zoom_level = function(){

    $("body").prepend('<div class="overlay" ' +
                'style="position:fixed; top:0%; left:0%; ' +
                'width:100%; height:100%; z-index:1;"></div>');

    var ratio = $("body .overlay:eq(0)").outerWidth() / $(window).width();
    $("body .overlay:eq(0)").remove();

    return ratio;
}

alert(zoom_level());

});

If you want the zoom level right after the pinch move, you will probably have to set a little timeout because of the rendering delay (but I'm not sure because I didn't test it).

pmrotule
  • 6,841
  • 3
  • 41
  • 49
0

Didn't test this for IE, but if you make an element elem with

min-width: 100%

then

window.document.width / elem.clientWidth

will give you your browser zoom level (including the document.body.style.zoom factor).

0

This answer is based on comments about devicePixelRatio coming back incorrectly on user1080381's answer.

I found that this command was coming back incorrectly in some instances too when working with a desktop, Surface Pro 3, and Surface Pro 4.

What I found is that it worked on my desktop, but the SP3 and SP4 were giving different numbers from each other and the desktop.

I noticed though that the SP3 was coming back as 1 and a half times the zoom level I was expecting. When I took a look at the display settings, the SP3 was actually set to 150% instead of the 100% I had on my desktop.

So, the solution to the comments should be to divide the returned zoom level by the scale of the machine you are currently on.

I was able to get the scale in the Windows settings by doing the following:

ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DesktopMonitor");
double deviceScale = Convert.ToDouble(searcher.Get().OfType<ManagementObject>().FirstOrDefault()["PixelsPerXLogicalInch"]);
int standardPixelPerInch = 96;
return deviceScale / standardPixelPerInch;

So in the case of my SP3, this is how this code looks at 100% zoom:

devicePixelRatio = 1.5
deviceScale = 144
deviceScale / standardPixelPerInch = 1.5
devicePixelRatio / (deviceScale / standardPixelPerInch) = 1

Multiplying by the 100 in user1080381's original answer then would give you a zoom of 100 (%).

0

On Chrome

var ratio = (screen.availWidth / document.documentElement.clientWidth);
var zoomLevel = Number(ratio.toFixed(1).replace(".", "") + "0");
Nicolas Giszpenc
  • 503
  • 4
  • 10
0

Have it currently working however still need to separate by browser. Tested successfully on Chrome(75) and Safari(11.1) (haven't found way for FF as of yet). It also gets the zoom value correct on retina display and calculations are triggered on resize event.

    private pixelRatio() {
      const styleString = "(min-resolution: 2dppx), (-webkit-min-device-pixel-ratio: 1.5),(-moz-min-device-pixel-ratio: 1.5),(min-device-pixel-ratio: 1.5)";
      const chromeRatio = (Math.round((this.window.outerWidth / this.window.innerWidth)*100) / 100);
      const otherRatio = (Math.round(window.devicePixelRatio * 100) / 100);
      const resizeValue = (this.isChrome()) ? chromeRatio : otherRatio;

      return resizeValue || (this.window.matchMedia && this.window.matchMedia(styleString).matches ? 2 : 1) || 1;
    }


  private isChrome():boolean {
    return (!!this.window.chrome && !(!!this.window.opera || this.window.navigator.userAgent.indexOf(' Opera') >= 0))
  }

  private chrome() {
    const zoomChrome = Math.round(((this.window.outerWidth) / this.window.innerWidth)*100) / 100;
    return {
      zoom: zoomChrome,
      devicePxPerCssPx: zoomChrome1 * this.pixelRatio()
    };
  }
Yogi
  • 185
  • 1
  • 4
0

try this

alert(Math.round(window.devicePixelRatio * 100));
Abd Abughazaleh
  • 1,259
  • 9
  • 28
-1

This is question was posted like ages back, but today when i was looking for the same answer "How to detect zoom in and out event", i couldn't find one answer that would fit all the browsers.

As on now : For Firefox/Chrome/IE8 and IE9 , the zoom in and out fires a window.resize event. This can be captured using:

$(window).resize(function() {
//YOUR CODE.
});
Bhumi Singhal
  • 7,459
  • 9
  • 43
  • 69
-1

here it does not change!:

<html>
 <head>
  <title></title>
 </head>
<body>
 <div id="xy" style="width:400px;">
  foobar
 </div>
 <div>
  <button onclick="alert(document.getElementById('xy').style.width);">Show</button>
 </div>
</body>
</html>

create a simple html file, click on the button. regardless of what zoom level: it will show you the width of 400px (at least with firefox and ie8)

  • @tfl: it's because you've fixed the width in inline-style. I've modified your sample to show my case (posted inside original question). – understack Nov 12 '09 at 11:22
-1

A workaround for FireFox 16+ to find DPPX (zoom level) purely with JavaScript:

var dppx = (function (precision) {
  var searchDPPX = function(level, min, divisor) {
    var wmq = window.matchMedia;
    while (level >= min && !wmq("(min-resolution: " + (level/divisor) + "dppx)").matches) {
      level--;
    }
    return level;
  };

  var maxDPPX = 5.0; // Firefox 22 has 3.0 as maximum, but testing a bit greater values does not cost much
  var minDPPX = 0.1; // Firefox 22 has 0.3 as minimum, but testing a bit smaller values does not cost anything
  var divisor = 1;
  var result;
  for (var i = 0; i < precision; i++) {
    result = 10 * searchDPPX (maxDPPX, minDPPX, divisor);
    maxDPPX = result + 9;
    minDPPX = result;
    divisor *= 10;
  }

  return result / divisor;
}) (5);
lexasss
  • 292
  • 1
  • 2
  • 8
  • It doesn't work as expected in Firefox (52) on MacBook with retina display – returns 2 when not in zoom. I created a fiddle: https://jsfiddle.net/Terite/wadkh3ea/ – Terite Mar 22 '17 at 15:20
-1

The problem lies in the types of monitor used, a 4k monitor vs standard monitor. Chrome is by far the smartest at being able to tell us what the zoom level is just by using window.devicePixelRatio, apparently it can tell what the pixel density is and reports back the same number to matter what.

Other browsers, not so much. IE and Edge are probably the worst, as they handle zoom levels much differently. To get the same size text on a 4k monitor, you have to select 200%, instead of 100% on a standard monitor.

As of May 2018, here's what I have to detect zoom levels for a few of the most popular browsers, Chrome, Firefox, and IE11. I have it tell me what the zoom percentage is. For IE, it reports 100% even for 4k monitors that are actually at 200%, but the text size is really the same.

Here's a fiddle: https://jsfiddle.net/ae1hdogr/

If anyone would care to take a stab at other browsers and update the fiddle, then please do so. My main goal was to get these 3 browsers covered to detect if people were using a zoom factor greater than 100% to use my web application and display a notice suggesting a lessor zoom factor.

Bill_VA
  • 713
  • 6
  • 9
-1

This may or may not help anyone, but I had a page I could not get to center correctly no matter what Css tricks I tried so I wrote a JQuery file call Center Page:

The problem occurred with zoom level of the browser, the page would shift based upon if you were 100%, 125%, 150%, etc.

The code below is in a JQuery file called centerpage.js.

From my page I had to link to JQuery and this file to get it work, even though my master page already had a link to JQuery.

<title>Home Page.</title>
<script src="Scripts/jquery-1.7.1.min.js"></script>
<script src="Scripts/centerpage.js"></script>

centerpage.js:

// centering page element
function centerPage() {
    // get body element
    var body = document.body;

    // if the body element exists
    if (body != null) {
        // get the clientWidth
        var clientWidth = body.clientWidth;

        // request data for centering
        var windowWidth = document.documentElement.clientWidth;
        var left = (windowWidth - bodyWidth) / 2;

        // this is a hack, but it works for me a better method is to determine the 
        // scale but for now it works for my needs
        if (left > 84) {
            // the zoom level is most likely around 150 or higher
            $('#MainBody').removeClass('body').addClass('body150');
        } else if (left < 100) {
            // the zoom level is most likely around 110 - 140
            $('#MainBody').removeClass('body').addClass('body125');
        }
    }
}


// CONTROLLING EVENTS IN jQuery
$(document).ready(function() {
    // center the page
    centerPage();
});

Also if you want to center a panel:

// centering panel
function centerPanel($panelControl) {
    // if the panel control exists
    if ($panelControl && $panelControl.length) {
        // request data for centering
        var windowWidth = document.documentElement.clientWidth;
        var windowHeight = document.documentElement.clientHeight;
        var panelHeight = $panelControl.height();
        var panelWidth = $panelControl.width();

        // centering
        $panelControl.css({
            'position': 'absolute',
            'top': (windowHeight - panelHeight) / 2,
            'left': (windowWidth - panelWidth) / 2
        });

        // only need force for IE6
        $('#backgroundPanel').css('height', windowHeight);
    }
}
Rob W
  • 315,396
  • 71
  • 752
  • 644
user1054326
  • 320
  • 1
  • 3
-3
function supportFullCss3()
{
    var div = document.createElement("div");
    div.style.display = 'flex';
    var s1 = div.style.display == 'flex';
    var s2 = 'perspective' in div.style;

    return (s1 && s2);
};

function getZoomLevel()
{
    var screenPixelRatio = 0, zoomLevel = 0;

    if(window.devicePixelRatio && supportFullCss3())
        screenPixelRatio = window.devicePixelRatio;
    else if(window.screenX == '0')
        screenPixelRatio = (window.outerWidth - 8) / window.innerWidth;
    else
    {
        var scr = window.frames.screen;
        screenPixelRatio = scr.deviceXDPI / scr.systemXDPI;
    }

    //---------------------------------------
    if (screenPixelRatio <= .11){ //screenPixelRatio >= .01 &&
      zoomLevel = "-7";
    } else if (screenPixelRatio <= .25) {
      zoomLevel = "-6";
    }else if (screenPixelRatio <= .33) {
      zoomLevel = "-5.5";
    } else if (screenPixelRatio <= .40) {
      zoomLevel = "-5";
    } else if (screenPixelRatio <= .50) {
      zoomLevel = "-4";
    } else if (screenPixelRatio <= .67) {
      zoomLevel = "-3";
    } else if (screenPixelRatio <= .75) {
      zoomLevel = "-2";
    } else if (screenPixelRatio <= .85) {
      zoomLevel = "-1.5";
    } else if (screenPixelRatio <= .98) {
      zoomLevel = "-1";
    } else if (screenPixelRatio <= 1.03) {
      zoomLevel = "0";
    } else if (screenPixelRatio <= 1.12) {
      zoomLevel = "1";
    } else if (screenPixelRatio <= 1.2) {
      zoomLevel = "1.5";
    } else if (screenPixelRatio <= 1.3) {
      zoomLevel = "2";
    } else if (screenPixelRatio <= 1.4) {
      zoomLevel = "2.5";
    } else if (screenPixelRatio <= 1.5) {
      zoomLevel = "3";
    } else if (screenPixelRatio <= 1.6) {
      zoomLevel = "3.3";
    } else if (screenPixelRatio <= 1.7) {
      zoomLevel = "3.7";
    } else if (screenPixelRatio <= 1.8) {
      zoomLevel = "4";
    } else if (screenPixelRatio <= 1.9) {
      zoomLevel = "4.5";
    } else if (screenPixelRatio <= 2) {
      zoomLevel = "5";
    } else if (screenPixelRatio <= 2.1) {
      zoomLevel = "5.2";
    } else if (screenPixelRatio <= 2.2) {
      zoomLevel = "5.4";
    } else if (screenPixelRatio <= 2.3) {
      zoomLevel = "5.6";
    } else if (screenPixelRatio <= 2.4) {
      zoomLevel = "5.8";
    } else if (screenPixelRatio <= 2.5) {
      zoomLevel = "6";
    } else if (screenPixelRatio <= 2.6) {
      zoomLevel = "6.2";
    } else if (screenPixelRatio <= 2.7) {
      zoomLevel = "6.4";
    } else if (screenPixelRatio <= 2.8) {
      zoomLevel = "6.6";
    } else if (screenPixelRatio <= 2.9) {
      zoomLevel = "6.8";
    } else if (screenPixelRatio <= 3) {
      zoomLevel = "7";
    } else if (screenPixelRatio <= 3.1) {
      zoomLevel = "7.1";
    } else if (screenPixelRatio <= 3.2) {
      zoomLevel = "7.2";
    } else if (screenPixelRatio <= 3.3) {
      zoomLevel = "7.3";
    } else if (screenPixelRatio <= 3.4) {
      zoomLevel = "7.4";
    } else if (screenPixelRatio <= 3.5) {
      zoomLevel = "7.5";
    } else if (screenPixelRatio <= 3.6) {
      zoomLevel = "7.6";
    } else if (screenPixelRatio <= 3.7) {
      zoomLevel = "7.7";
    } else if (screenPixelRatio <= 3.8) {
      zoomLevel = "7.8";
    } else if (screenPixelRatio <= 3.9) {
      zoomLevel = "7.9";
    } else if (screenPixelRatio <= 4) {
      zoomLevel = "8";
    } else if (screenPixelRatio <= 4.1) {
      zoomLevel = "8.1";
    } else if (screenPixelRatio <= 4.2) {
      zoomLevel = "8.2";
    } else if (screenPixelRatio <= 4.3) {
      zoomLevel = "8.3";
    } else if (screenPixelRatio <= 4.4) {
      zoomLevel = "8.4";
    } else if (screenPixelRatio <= 4.5) {
      zoomLevel = "8.5";
    } else if (screenPixelRatio <= 4.6) {
      zoomLevel = "8.6";
    } else if (screenPixelRatio <= 4.7) {
      zoomLevel = "8.7";
    } else if (screenPixelRatio <= 4.8) {
      zoomLevel = "8.8";
    } else if (screenPixelRatio <= 4.9) {
      zoomLevel = "8.9";
    } else if (screenPixelRatio <= 5) {
      zoomLevel = "9";
    }else {
      zoomLevel = "unknown";
    }

    return zoomLevel;
};
ali
  • 11
  • 1
  • 7
    Kindly also explain how your code works. That will be helpful if some novice finds your answer. – displayName Sep 22 '15 at 23:34
  • I created a fiddle: https://jsfiddle.net/Terite/5n1bk9do/ As @AlexeySh. mentioned, it doesn't work as expected on retina display in Chrome (56), Firefox (52). It also shows 0 in zoom on Safari (10). – Terite Mar 22 '17 at 14:57
  • That's a lot of `else if`s – Nanoo Jul 24 '20 at 02:41