What is the best way to detect retina support on a device using JavaScript?

Right now I am using this function:

function is_retina_device() {
    return window.devicePixelRatio > 1;
}

But its simplicity scares me. Is there a more thorough check?


According to everything that I've read recently, browsers seem to be moving towards the resolution media query expression. This is instead of device-pixel-ratio that is being used in the currently accepted answer. The reason why device-pixel-ratio should only be used as a fallback is because it is not a standard media query.

According to w3.org:

Once upon a time, Webkit decided a media query for the screen resolution was needed. But rather than using the already-standardized resolution media query, they invented -webkit-device-pixel-ratio.

View Full Article

Resolution Media Query Documentation

Since resolution is standardized and therefore the future let's use that first in the detection for future proofing. Also because I'm not sure if you want to detect only high dppx devices or only retina(Apple only) devices, I've added one of each. Finally just as a note, the Apple detection is just user agent sniffing so can't be depended on. Note: for the isRetina function I'm using a dppx of 2 instead of 1.3 because all retina apple devices have a 2dppx.

Note it appears that MS Edge has some issues with non integer values

function isHighDensity(){
    return ((window.matchMedia && (window.matchMedia('only screen and (min-resolution: 124dpi), only screen and (min-resolution: 1.3dppx), only screen and (min-resolution: 48.8dpcm)').matches || window.matchMedia('only screen and (-webkit-min-device-pixel-ratio: 1.3), only screen and (-o-min-device-pixel-ratio: 2.6/2), only screen and (min--moz-device-pixel-ratio: 1.3), only screen and (min-device-pixel-ratio: 1.3)').matches)) || (window.devicePixelRatio && window.devicePixelRatio > 1.3));
}


function isRetina(){
    return ((window.matchMedia && (window.matchMedia('only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx), only screen and (min-resolution: 75.6dpcm)').matches || window.matchMedia('only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min--moz-device-pixel-ratio: 2), only screen and (min-device-pixel-ratio: 2)').matches)) || (window.devicePixelRatio && window.devicePixelRatio >= 2)) && /(iPad|iPhone|iPod)/g.test(navigator.userAgent);
}

If you want it for images you can use retinajs or this code is a common response to detect it:

function isRetinaDisplay() {
        if (window.matchMedia) {
            var mq = window.matchMedia("only screen and (min--moz-device-pixel-ratio: 1.3), only screen and (-o-min-device-pixel-ratio: 2.6/2), only screen and (-webkit-min-device-pixel-ratio: 1.3), only screen  and (min-device-pixel-ratio: 1.3), only screen and (min-resolution: 1.3dppx)");
            return (mq && mq.matches || (window.devicePixelRatio > 1)); 
        }
    }

Actually, the code you're using in your question is just completely right if you care only about modern browsers. (See: http://caniuse.com/#feat=devicepixelratio)

All modern browsers have it implemented, and older browsers would be just served your lower resolution images. I don't expect IE10- to show up on a retina / high-res device. Also, is using CSS checks in JavaScript not more weird than using a native window property?

Heck, devicePixelRatio browser support is even better than the resolution spec. (See: http://caniuse.com/#feat=css-media-resolution)

I'd say it's actually very safe to use, we use it in production websites with over 10 million visitors a month. Works as expected.

The only thing I'd change is the function name, as the need to load high res images doesn't technically mean the screen is retina. Actually, you don't even need a number check, as undefined > 1 results in false.

function is_high_resolution_screen() {
  return window.devicePixelRatio > 1;
}

devicePixelRatio is not reliable at all. when you zoom in to 200%, the window.devicePixelRatio will return you 2, but you are not on a retina display.