Detecting Retina Displays and Other High-DPI Screens

by kirupa   |   26 August 2016

It used to be that detecting screen resolution was enough to ensure people saw your content properly. You had big screens. You had small screens. The amount of pixels these devices had directly correlated with the screen size. As displays started to get more pixels crammed into ever smaller regions, just knowing the resolution was no longer enough. It became important to know about the pixel density - commonly referred to as dots per inch or DPI.

If you aren't too familiar with DPI, don't worry too much about it. This Wikipedia article will give you a good overview. The 10 second version is this: The more dots you have per inch, the more detailed what you are viewing will be when compared to viewing it on something with fewer dots per inch. For something to be considered a high-DPI screen, I'm going to use a minimum value of 192. This is what is generally accepted by many people, and it also happens to correspond to the lower end of the DPI value a Retina display on an Apple laptop would return as well.

Anyway, this article really isn't about teaching you the mysteries of DPI. This article is more around the technical solutions we have for detecting the DPI in both CSS and JavaScript.

Onwards!

OMG! An Animation Book Written by Kirupa?!!

To kick your animations skills into the stratosphere, everything you see here and more (with all its casual clarity!) is available in both paperback and digital editions.

BUY ON AMAZON

The Example

Before we get into the technical weeds, let's look at a simple example that uses the snippets of code that you will see. In the following box, you'll see the words High-DPI / Retina! or NOT High DPI / Retina! displayed depending on the type of screen you are viewing this page in:

No result!

In the following sections, we'll take a look the pieces of code that came together to make this example work to display the appropriate text for your screen type. If you don't want to read further and just want to cut to the chase, you can see this example in its own page and view the source. It is a far less entertaining way to go about this, so I still think you should read on :P

General Approach

If you are looking for a magical property that tells you what your current device DPI is, then you are in for some bad news. There is no such property. What we do have are ways of detecting when a particular DPI range has been hit. We do that using media queries and the min-resolution and min-device-pixel-ratio media features. There is just one more thing to cover. DPI values are represented as numbers. The higher the DPI, the more pixels are packed into a tiny part of the screen.

We'll talk more about them in a little bit, so don't worry if all of that sounds like gibberish. Now, with all that said, let's get to the markup and code.

The CSS Approach

In CSS, you can use a media query with the min-resolution feature to check for a Retina / high-dpi screen:

@media (min-resolution: 192dpi) {
   body {
     background-color: yellow;
   }
}

The value of 192 makes an appearance here. As mentioned in the introduction, a DPI value of 192 is a good minimum for designating a screen as being high-dpi (and Retina) capable. Looks like we are done, right? Well...

While this media query works for many users, the min-resolution media feature is still pretty new. To reach the most people, you need to also throw in the min-device-pixel-ratio media feature with a value of 2:

@media (-webkit-min-device-pixel-ratio: 2),
       (min-device-pixel-ratio: 2),
       (min-resolution: 192dpi) {

   body {
     background-color: yellow;
   }
}

The min-device-pixel-ratio media feature is deprecated by all the new browsers, so don't rely on it working for a very long time. Use it in addition to min-resolution to reach the most people, but don't use it just by itself.

The JavaScript Approach

You aren't limited to a CSS-only solution detecting whether you are running on a Retina/high-dpi screen. You can use the matchMedia method that lives on our window object to use our earlier media query approach in the world of JavaScript as well.

Take a look at the following snippet:

var query = "(-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2), (min-resolution: 192dpi)";

if (matchMedia(query).matches) {
  // do high-dpi stuff
} else {
  // do non high-dpi stuff
}

The matchMedia method takes a media query as its argument, and the media query we are using is the exact one we used in our CSS approach earlier. If the media query evaluates to true, matchMedia returns true. Of course, if the media query evaluates to false, matchMedia returns a false as well.

What about window.devicePixelRatio?

Almost all browsers have support for a property called devicePixelRatio. What this property does is return the ratio of the height of a physical pixel on your display with the size of what is known as a device-independent pixel. Think of a device-independent pixel as a virtual pixel. This virtual pixel is one your computer uses internally before translating it into a physical pixel, and it is used frequently as a convenience where apps don't have to worry about the physical pixels available and so on when thinking about where to position something or figuring out how big/small to size an element.

Getting back to our point (and simplifying things), the devicePixelRatio property returns a number that is the ratio of the vertical height of a physical pixel and a virtual pixel. This number varies wildly with application zoom level and other factors. Because of that, it is a less reliable measurement compared to our min-resolution and min-device-pixel-ratio media query feature.

Conclusion

It is strange that there isn't a reliable way to check for the current DPI in modern browsers today. The CSS media query approach works well, but it feels like a roundabout way of doing things. What if you wanted to check for DPIs other than 192? Is the expectation that you create multiple media queries using each DPI value? That gets really messy. Not being able to figure out the exact DPI value and react accordingly seems like a bummer. Until that gets addressed, hopefully the CSS and JS workarounds provided here help.

If you have a question about this or any other topic, the easiest thing is to drop by our forums where a bunch of the friendliest people you'll ever run into will be happy to help you out!

THE KIRUPA NEWSLETTER

Get cool tips, tricks, selfies, and more...personally hand-delivered to your inbox!

( View past issues for an idea of what you've been missing out on all this time! )

WHAT DO YOU THINK?

NEWSLETTER

No spam. No fluff. Just awesome content sent straight to your inbox!

Awesome and high-performance web hosting!
BACK TO TOP
new books - yay!!!