Browser zooming and CSS layout issues

Browser zooming and CSS layout issues

  • Posted on: January 20, 2016
  • By:

Browsers have a zoom functionality, to zoom in or out, enlarging or shrinking the content in the browser window (using CTRL plus scrollwheel on mouse, or CTRL with + or -). I guess most of the time (no research here), people would zoom in, enlarging elements on screen to improve legibility. There’s also an option to only zoom in/out text, leaving all other elements (like formfields, buttons…) in the original format.
One of our customers tends to zoom out, to show more content at once (as our screens happen to contain a lot of data). I guess it saves them having to purchase new, higher resolution screens for their employees, to get the benefit of a wider view on their data (to the detriment of their employees’ eyes).
I never noticed any layout issues with zoomed in content, but there was a small issue with some range fields and calendar components becoming misaligned when zooming out. And whatever I tried (padding, margin, EMs in stead of PXs, …) I did not get it to comply. Now, maybe the underlying document structure wasn’t up to scratch. It’s 10 year old web app, but at least it wasn’t using tables for form layout (because that was the right thing to do, right?), it does mean all these small, annoying misalignments across different browsers.

Anyway, I’m just wanted to document a solution I found to this particular problem, which solved this particular issue for me, and maybe might help you too. Though I couldn’t find anything referencing this for zooming purposes.
The trick is (drumroll), using min-device-pixel-ratio for CSS media queries. It might look a bit hacky, but it worked (without doing a whole refactoring of the existing css layout).

When zooming in/out in the browser (but not text-only zoom), the browser would change the registered device-pixel-ratio (try it in a JavaScript console with window.devicePixelRatio), which means you can target different devicePixelRatios using CSS media queries:
@media only screen and (min-device-pixel-ratio: 1){
body{background-color:aqua}
}

or for some backwards compatibility:
@media
only screen and (-webkit-min-device-pixel-ratio: 1),
only screen and ( min--moz-device-pixel-ratio: 1),
only screen and ( min-device-pixel-ratio: 1){
body{background-color:aqua}
}

A device-pixel-ratio of 1 is the basic state of any basic (cheap) PC screen out there, mostly 1920×1080 nowadays.
Normally, device-pixel-ratio would be used to target high pixel density screens, like Apple’s so called “retina” displays, or high resolution Android tablets, which would have a device-pixel-ratio of 2 (or at least more than 1). For example, this page has an overview of several phones/tablet devices and their device-pixel-ratio: http://mydevice.io.
When zooming out in a desktop browser though, the device-pixel-ratio becomes less than 1.
And as such I can target any discrepancies in the layout when a user zooms out:
@media
only screen and (-webkit-min-device-pixel-ratio: 0.1),
only screen and ( min–moz-device-pixel-ratio: 0.1),
only screen and ( min-device-pixel-ratio: 0.1){
.calendar{ margin-top: 20px}
}

@media
only screen and (-webkit-min-device-pixel-ratio: 0.35),
only screen and ( min–moz-device-pixel-ratio: 0.35),
only screen and ( min-device-pixel-ratio: 0.35){
.calendar{ margin-top: 10px}
}

@media
only screen and (-webkit-min-device-pixel-ratio: 0.55),
only screen and ( min–moz-device-pixel-ratio: 0.55),
only screen and ( min-device-pixel-ratio: 0.55){
.calendar{ margin-top: 5px}
}

@media
only screen and (-webkit-min-device-pixel-ratio: 1),
only screen and ( min–moz-device-pixel-ratio: 1),
only screen and ( min-device-pixel-ratio: 1){
.calendar{ margin-top: 2px}
}
The moment the user zoomed out, the 2px margin did not work anymore, and the layout would be broken (slightly).
Using a margin of 5px fixed it, for a lower-than-1 device-pixel-ratio. Zooming out even more, again the margin would fail, and I’d need 10px,…
Of course, min-device-pixel-ratio: 0.1 is ridiculous (the screen becomes illegible), but it covered all the bases.
Also, I’m using min-device-pixel-ratio (and not device-pixel-ratio) so we can target ranges, from 0.1 to 0.349999, 0.35 to 0.549999, …

Try it out with different body colors. Fun, fun, fun…