There we go again. The desktop browsers, over my strenuous objections, decided to treat DPR (device pixel ratio) as a variable instead of a constant when the user uses page zooming instead of pinch zooming.
The advantages or disadvantages of this decision are not what currently interests me, though I continue to have my doubts.
What we’re going to study today is the practical application of that idea: if DPR is a variable, responsive images should respond to page zoom. Do they? Safari doesn’t, Firefox does but has weird rounding, while Chrome/Opera and Edge each have their own bug but do normal rounding.
There are two ways of zooming in on a web page: page zoom and pinch zoom.
All mobile browsers (so far) only support pinch zoom, which you can see visualised here. Use X and Z to pinch zoom in and out, and you’ll see that the visual viewport changes size, while the layout viewport keeps its dimensions.
All desktop browsers support page zoom, which is the old-fashioned zooming with Ctrl/Cmd + or -. Here, the layout viewport changes dimensions, since all CSS pixels are enlarged, and therefore less of them fit in the browser window, and percentual widths and such have to be recalculated relative to the new layout viewport. (I don’t have a visualisation — sorry.)
Nowadays, Chrome and Edge on desktop also support pinch zoom. In Chrome, double-click on an element or pinch on the trackpad of your Mac to get the effect. (I don’t know how it would work without a trackpad, or on non-Mac computers.) In Edge I don’t know how it works. It’s a menu with a magnifying glass and + and - signs. I got it once by accident, dismissed it, and now I have no clue how to access it.
Anyway, the point here is not so much the type of zooming or the layout viewport, but the behaviour of devicePixelRatio (DPR).
So pinch zoom uses DPR as a constant, while page zoom makes it a variable. I do not like this sort of differences.
But anyway, the issue here is not my preferences, but responsive images-x. Desktop browsers make a godawful mess of it.
Take this sample code; you can use a test page here:
<img id="test" srcset="pix/respimg1x.png 1x, pix/respimg2x.png 2x, pix/respimg3x.png 3x" src="pix/respimbpng.png" alt="Alt text" width="320" height="150">
On mobile this is simple: read out the device’s DPR, select an image, load it, done.
In a page zoom environment, where DPR is a variable, things get more complicated. Will the browser adjust the image as the user page zooms in and out? Is this a desired effect? I can now answer the first question, but the second question has never been properly treated (or if it has I haven’t found the article yet).
First, Safari (9). It treats DPR as a constant, and therefore the responsive image does not react to page zooming. So far so good; theory and practice agree here.
Theoretically speaking, if DPR increaes or decreases, the responsive image should change. Makes sense, no — if you think variable DPR is a good idea. In practice browsers are kind-of confused.
In Chrome (49) and Opera (35) the responsive image does not react to page zoom. That is, if you enter the page with a DPR of 1, the 1x image will be loaded and not replaced, however much you zoom. However, if you load the page at DPR 2, the 2x image will be loaded and not replaced. This is not the best application of the principle, I think: if you want responsive images to react to page zoom, DO SO, and don’t mess around with half measures.
HOWEVER. If you zoom to DPR 2, reload and get the 2x image, then zoom back to DPR 1 and then reload, you continue to get the 2x image. Apparently, what counts in Chrome is not the current page zoom level but the maximum it has ever reached in this session. You have to close the window to reset the responsive image.
I’m not even sure this is a bug or desired behaviour. It’s weird enough to be a bug, but you never know what kind of rationalisation the Chrome team can come up with.
In Edge (13) the image responds to page zoom. It goes up to 2x, and then to 3x. However, if you zoom out, it doesn’t go back to 2x and 1x. This, I assume, is a bug pure and simple that will be fixed. Reloading the page works: the responsive image reacts to the current DPR.
In Firefox (45), finally, the image reponds to page zoom in and out. This is the most pure application of the theory of variable DPR, so no more questions here (though I continue to doubt the principle).
If you use pinch zoom the responsive image does not react. (I couldn’t test this in Edge as much as I wanted, but I think it is the case). That, too, is theoretically fine, since DPR doesn’t change on pinch zoom.
There’s one more thing to consider: rounding. My example uses a simple 1x, 2x, and 3x. Exactly when does the browser move from one image to the next? How does it round DPR?
By now you won’t be surprised that browsers disagree. Chrome and Edge use mathematical rounding, where DPR 1.5 to 2.49 count as 2, and so on. Firefox, however, switches to the next image as soon as the DPR goes above 1 or 2. Has this been specced? In any case at least one browser gets it wrong.
Lots of work to do in this area, that’s for sure. Also, somebody should test this sort of stuff. You’re lucky that I’m working on a project that requires a responsive images support detect, or nobody would have ever noticed this mess.
If you like this blog, why not donate a little bit of money to help me pay my bills?