49

I want to find the ratio between CSS pixels and device pixels.

Edit: I should have realized that this is just zoom level. I've added an answer to the canonical reference on zoom levels.

CSS pixels are the unit we use for almost everything--it's what element.style.width, element.clientWidth, element.offsetWidth etc. mean. Device pixels are the pixels that the browser actually paints to. A few properties are measured in device pixels, e.g. window.screen.width, which is the screen size (e.g. 1024) that doesn't change when the user zooms in.

Motivation: when the user zooms in, I want to increase a canvas's width and height (while keeping style.width and style.height the same CSS pixel value), scale() the context, and redraw on a crisper upscaled canvas.

I've read Quirksmode's A Tale of Two Viewports and High DPI on Surfin' Safari, but neither of them say how to get the ratio. The only ideas I have so far are to collect mousemoves and measure change in event.clientX divided by change in event.screenX, or to programatically create media queries using moz--min-device-pixel-ratio, use getComputedStyle() to test whether the rule matched, and narrow it down with a binary search. I hope there's a easier/more reliable way.

Edit: I've tried using the @media (-webkit-min-device-pixel-ratio:1) queries with Chrome, Safari, and Firefox 4, and apparently Webkit treats the property as a constant device pixel to screen pixel ratio (which doesn't change with zoom), whereas Firefox 4 treats it as device pixel to CSS pixel ratio (which increases when you zoom in). So in Firefox 4, I can discover the CSS pixel / device pixel ratio using a binary search, but not with Webkit.

Community
  • 1
  • 1
yonran
  • 18,156
  • 8
  • 72
  • 97
  • whilst flash dependent, you might find this informative: http://stackoverflow.com/questions/5024493/browser-viewport-size-in-device-pixels/ – jedierikb Mar 01 '11 at 19:27
  • 2
    This is a good question but several years old now. One of the answers mentions FF29 and we are now at 53. Can you choose the best answer and offer some update as to the status of this information, time permitting? :-) – Nolo May 09 '17 at 16:01

4 Answers4

72

You can use window.devicePixelRatio in Webkit based browsers to get the device pixel ratio directly in JavaScript. I have used this on Google Chrome, Android browsers (2.2+) and Mobile Safari. I have no idea about other browsers though.

MiniGod
  • 3,683
  • 1
  • 26
  • 27
Tanzeel Kazi
  • 3,797
  • 1
  • 17
  • 22
  • 4
    `window.devicePixelRatio` works in Opera (Presto 2.8+) http://www.opera.com/docs/specs/presto28/#changes – ryanve Oct 25 '11 at 20:06
  • 7
    window.devicePixelRatio === 1 in Kindle Fire HD 7", even though it has a pixel density of 150%... – Per Quested Aronsson Jun 16 '13 at 20:44
  • 1
    Firefox (as of v.29) still incorrectly calculates `window.devicePixelRatio` if the user has zoomed their window. Firefox renders the page at the device's pixel ratio (example: 2.0 for "Retina" type displays), but then returns the actual calculated pixel ratio (ex: at 3x window zoom, the devicePixelRatio would return 2.0*3 = 6.0). This causes mayhem for `canvas` elements. – bob Jun 10 '14 at 02:50
  • 1
    As of Firefox 18 Mozilla alters the devicePixelRatio value when the browser is zoomed so 'device..' is deceptive. – davidcondrey Sep 10 '14 at 19:23
25

You can always use the following method and it would work in all the browsers

window.getDevicePixelRatio = function () {
    var ratio = 1;
    // To account for zoom, change to use deviceXDPI instead of systemXDPI
    if (window.screen.systemXDPI !== undefined && window.screen.logicalXDPI       !== undefined && window.screen.systemXDPI > window.screen.logicalXDPI) {
        // Only allow for values > 1
        ratio = window.screen.systemXDPI / window.screen.logicalXDPI;
    }
    else if (window.devicePixelRatio !== undefined) {
        ratio = window.devicePixelRatio;
    }
    return ratio;
};
abhinav sharma
  • 251
  • 3
  • 3
3

There is a much better CSS/JS solution:

/** sample media query for pixel-ratio=2" **/
@media  
(-webkit-min-device-pixel-ratio: 2), 
(min-resolution: 192dpi) { 
  .pixel-ratio-holder:before {
   content: "2";
  }
}


function jsPixelRatio(){
   return window.getComputedStyle(document.querySelector('.pixel-ratio-holder'), 'before').getPropertyValue('content').replace(/[^a-z]/g,'') * 1;
}
androidavid
  • 1,258
  • 1
  • 11
  • 20
0

How to get device Pixel Ratio

This example uses window.devicePixelRatio as a starting point AND also window.matchMedia() Web API as a fallback calculation.

The browser support for both those features is pretty good, so this should work great for most of use cases.

Here is a function that retrieves this information, originally written by PatrickJS and published as a GitHub Gist:

function getDevicePixelRatio() {
    var mediaQuery;
    var is_firefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;

    if (window.devicePixelRatio !== undefined && !is_firefox) {
        return window.devicePixelRatio;
    } else if (window.matchMedia) {
        mediaQuery = "(-webkit-min-device-pixel-ratio: 1.5),\
          (min--moz-device-pixel-ratio: 1.5),\
          (-o-min-device-pixel-ratio: 3/2),\
          (min-resolution: 1.5dppx)";
        if (window.matchMedia(mediaQuery).matches) {
            return 1.5;
        }
        mediaQuery = "(-webkit-min-device-pixel-ratio: 2),\
          (min--moz-device-pixel-ratio: 2),\
          (-o-min-device-pixel-ratio: 2/1),\
          (min-resolution: 2dppx)";
        if (window.matchMedia(mediaQuery).matches) {
            return 2;
        }
        mediaQuery = "(-webkit-min-device-pixel-ratio: 0.75),\
          (min--moz-device-pixel-ratio: 0.75),\
          (-o-min-device-pixel-ratio: 3/4),\
          (min-resolution: 0.75dppx)";
        if (window.matchMedia(mediaQuery).matches) {
            return 0.7;
        }
    } else {
        return 1;
    }
}

CanIUse: window.devicePixelRatio, Window.matchMedia()

Useful links: MDN - window.devicePixelRatio, MDN - Window.matchMedia()

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Andrii Verbytskyi
  • 7,155
  • 3
  • 47
  • 38
  • 1
    In the future, when you adapt code or content from another source, please be sure that you [reference](https://stackoverflow.com/help/referencing) it appropriately. You had the link here, but you buried it at the bottom under the heading "source", instead of including it directly with the copied code. Also, you need to include the name of the original author. I've made the changes for you here; please keep this in mind going forward. Thank you! – Cody Gray - on strike Feb 20 '19 at 18:04