Jonesing for dpi and dppx

Getting the output resolution of a screen from a web browser is not as simple as it might seem.

The old trick of setting a div as “1in” wide and then counting pixels only ever results in 96dpi (dpi in browsers is actually “dots per CSS inch” — and a “CSS inch” is defined as 96px — defeating the purpose of the exercise).

We’ve been able to create resolution dependent media queries for nearly 10 years now — and Stack Overflow is still littered with bad ideas to inaccurately measure the real-world dpi of a viewport.

The dream of dpi

Although dpi is not accessible directly in JS, we can derive a dpi value from a browser using methods like looping “media.match” on resolution media queries, but don’t be deceived, it still counts an inch as a CSS inch, ie, 96pixels, so it’s still not terribly useful.

But we still have dppx

Almost all browsers support the JS property `window.devicePixelRatio`, so we can access screen dppx figure directly.

A Codepen to output the dppx, screen and viewport sizes of your screen (or in this case an iframe).

Using a javascript derived dppx value for styling purposes would be madness, as we should be using the method built for this purpose — resolution media queries @media (min-resolution: 2dppx) { ... }. But knowing the dppx gives other possibilities inside your site/app, including differentiating (or reporting analytics on) Android phones.

Samsungs, Sonys, LGs, Huaweis — pretty much any non-Nexus phone — have the same 360px wide viewport as each other (remember, that’s in CSS pixels), but have either 720p, 1080p or super dense screens.

With dppx we can differentiate between categories like an old Galaxy S2 at 1.50dppx, a low-end 2.00dppx Galaxy J7, a mid-range 3.00dppx Galaxy S5, or a high-end 4.00dppx Galaxy S7.

Could you deduce a CPU speed difference from this? The honest answer should be that it’s not accurate, but if you have no other data to go on…

Using dppx and more to improve Google Analytics.

Using dppx, we at Stendahls separate Android phones into bands, based on when a certain spec of screen dppx would have constituted a “flagship” device. It’s a pretty approximate measure, but that’s the point, we only need to know the mix of users capabilities so that we target them more effectively and don’t kid ourselves into leaving people out. Along with other peripheral javascript properties like colour gamut and forceTouch, we also try to pull out more detail about iPhones and iPads: https://stendahls.github.io/ga-device-deep/

Notes from the quirky edges

It was while trying to get around the iOS screen size orientation “bug” I discovered more curiosities. All iOS devices see the portrait orientation as default — that means at 0° (and landscape as 90° or -90°). Android phones and 7" 16:9 tablets (eg Nexus 7) are exactly the same. But Android 10" 16:9 tablets (eg Nexus 10) almost always consider landscape orientation as the default 0° view. I’m not sure about 4:3 Android tablets like the Samsung Tab A, I’d expect them to follow the lead of the iPad. Even desktop monitors report orientation, the Dell monitor I use in rotated orientation reported 90° orientation to the browser when the primary screen on the connected laptop reported 0°.

When changing the screen zoom at an OS level, browsers seem to report only the native screen dppx.

  • In iOS an iPhone6 in OS level “zoomed” mode (where the home-screen icons appear larger) gives Safari a 320px wide viewport instead of regular 375px but incorrectly reports the native 2.00dppx and so a 640x1136px physical screen (the same as an iPhone5).
  • On MacOS there’s a similar story. The 2014/15 Retina MacBook Pro 13" screen has a CSS pixel equivalent size of 1280x800px (2560x1600 actual pixels at 2dppx), but through system preferences, it can be adjusted all the way up to a CSS pixel size of 1680x1050px (1.52dppx as the physical pixel size of course still the same). But the browser still reports 2.00dppx, thereby calculating the actual screen size as a huge (and incorrect) 3360x2100px.
  • I haven’t tried Android or Windows yet.

Zooming at a browser window level appears to follow a slightly quirkier path:

  • In Chrome (55):
    Changed: dppx, viewport size (in CSSpx).
    Unchanged: screen size (in CSSpx).
  • In Safari (10.0):
    Changed: viewport size (in CSSpx).
    unchanged: dppx, screen size (in CSSpx).
  • In Firefox (50), IE11 and Edge (14):
    Changed: dppx, viewport size (in CSSpx), screen size (in CSSpx)

After trying and failing to discover what the specs say should happen, I’m left with my own expectations. Dppx and viewport should of course reflect window zooming (two strikes against Safari there), but I believe FF, IE and Edge to be the most correct browsers; in a zoomed window situation, knowing the potential screen estate is more important than knowing what it is at a normal zoom level. It might confuse your analytics though, unless you’re aware of this edge case.

Ex Londoner, new Gothenburger. Data insights at Polestar.