How to detect page zoom level in all modern browsers?

Viewed 354577
  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>
30 Answers

On Chrome

var ratio = (screen.availWidth / document.documentElement.clientWidth);
var zoomLevel = Number(ratio.toFixed(1).replace(".", "") + "0");

try this

alert(Math.round(window.devicePixelRatio * 100));

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 (%).

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

This detects scale.

html code:

<body id="blog">

js:

function scale(){
return Math.round(100/(d.getElementById('blog').offsetWidth/d.getElementById('blog').getBoundingClientRect().width))/100;
}

Zoom factor and scale are not to be confused with each other. Users control "zoom"; "scale" is a CSS transformation. 11 years and 10 months ago, however, understack noted:

Basically I want to know the dimension of a DIV at 100% zoom.

This does that. I use it in conjunction with @media queries to detect in JavaScript device scaling, i.e. 360x720 might apply 0.5 scaling; 720x360, 0.75.

var d=document;

I used a different approach, i created a dom element with a fixed height and width of 100px, position fixed and opacity of 0, basically a hidden element.

I then used dom-to-image to capture this element as an image which might sound like overkill but i wanted a bullet proof solution and we were already using this package anyways, then validated the output image width, if it came back with 110, the zoom is at 110%, it's very accurate.

const ORIGINAL_ZOOM_SIZE = 100;
async function isValidateZoomLevel() {
    const base64Render = await domToImage({
      ref: hiddenElementReference,
    });
    const pixleRatio = Math.round(window.devicePixelRatio);
    return new Promise((resolve, reject) => {
      const img = new Image();
      img.onload = () => resolve(ORIGINAL_ZOOM_SIZE === img.width / pixleRatio && ORIGINAL_ZOOM_SIZE === (img.height / pixleRatio));
      img.onerror = reject;
      img.src = base64Render; 
    });
  }

I fixed by the below code.

HTML:

<div class="mt-5"
        [ngStyle]="getStyles()">

TS:

getStyles() {
        const screenWidth = screen.width;
        const windowWidth = window.innerWidth;
        if (windowWidth != screenWidth) {
            const percentDifference = Math.ceil((screenWidth / windowWidth) * 100);
            if (percentDifference > 100) {
                this.bannerBackgroundImageSize = '20%, 74%';
            } else if (percentDifference === 100) {
                this.bannerBackgroundImageSize = '20%, 72%';
            } else if (percentDifference >= 90 && percentDifference <= 99) {
                this.bannerBackgroundImageSize = '25%, 70%';
            } else if (percentDifference >= 80 && percentDifference <= 89) {
                this.bannerBackgroundImageSize = '28%, 68%';
            } else if (percentDifference >= 75 && percentDifference <= 79) {
                this.bannerBackgroundImageSize = '29%, 67%';
            } else if (percentDifference >= 67 && percentDifference <= 74) {
                this.bannerBackgroundImageSize = '30%, 65%';
            } else if (percentDifference >= 50 && percentDifference <= 66) {
                this.bannerBackgroundImageSize = '30%, 61%';
            } else if (percentDifference < 50) {
                this.bannerBackgroundImageSize = '30%, 58%';
            }
        } else {
            this.bannerBackgroundImageSize = '20%, 72%';
        }
        const myStyles = {
            'background-size': this.bannerBackgroundImageSize,
        };
        return myStyles;
    }

I Hope this will work with all zoom levels and it can be considered with all styles.

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.

Related