DEV Community

Vladimir Elchinov for Session Replay

Posted on

Browser Zoom Changes the Size of a CSS Pixel, and Your Bug Report Cannot See It

A report arrives with a screenshot. The sidebar has collapsed into the narrow layout, on a desktop, where it should never collapse. You ask for their screen size, because that is what the layout depends on. They say 1920 by 1080, which is true.

You open the page at 1920 by 1080. The sidebar is fine.

Zoom is not magnification

The model most of us carry is that browser zoom works like a magnifying glass held over a finished page: same layout, bigger pixels. It does not. It changes the unit the layout is written in.

MDN, on devicePixelRatio:

When a page is zoomed in (made larger), the size of a CSS pixel increases, and so the devicePixelRatio value increases.

The size of a CSS pixel increases, so everything measured in CSS pixels has fewer of them to work with. A window 1920 device pixels wide at 125% zoom hands your stylesheet a viewport of about 1536 CSS pixels, and your (max-width: 1600px) rule is not misfiring when it collapses the sidebar. It is correct. The viewport genuinely is narrower than 1600 of the unit the rule is written in.

So there is no bug in the layout and no error in the report. There are two different widths, and the only one either of you mentioned is the one that decides nothing.

They will not tell you, because they do not know

This would be a harmless difference if zoom were something people did and then undid. From Chrome's own help:

The chosen zoom level will be saved for this specific site and won't affect other sites.

Saved, for your site specifically. Somebody held ctrl and turned a scroll wheel eight months ago, or zoomed in once to read a small label, and your site has rendered at 110% for them ever since. It survives a restart, which is why "I restarted the browser and it is still broken" is a perfectly consistent thing for them to report.

It is also not a state they can see, so asking whether they are zoomed in gets an honest no.

And it is worth remembering why many people are zoomed in: because the text is too small for them to read at 100%. "Press ctrl+0" is not a fix for that person. It is a request that they go back to using your site uncomfortably.

The number you would reach for cannot answer it

Having learned that devicePixelRatio moves with zoom, the obvious next step is to log it. It will not tell you what you want to know.

MDN defines it as "the ratio of the resolution in physical pixels to the resolution in CSS pixels for the current display device". The display's own density and the page's zoom both change that ratio, so a single reading of 1.5 is either a high density screen at 100% or an ordinary one at 150%, and nothing in the number separates the two.

The other scaling number does not close the gap. visualViewport.scale returns "the pinch-zoom scaling factor applied to the visual viewport", and MDN is explicit that pinch-zooming "does not affect devicePixelRatio, because this magnifies the page without changing the size of a CSS pixel". One number carries desktop zoom blended with display density. The other carries pinch-zoom alone. Neither of them reports a zoom level, and no standard property does.

People do estimate it anyway, usually by comparing one window measurement against another. That is an inference built from two numbers that each move for their own reasons, and a bug report wants a reading.

Record the decision, not the zoom

The move that works is to stop trying to recover the zoom level and record what the layout actually decided:

const layout = {
  // the width the rules saw, in the unit the rules are written in
  viewport: [window.innerWidth, window.innerHeight],
  dpr: window.devicePixelRatio,
  pinch: window.visualViewport?.scale,
  // the branches, recorded rather than reconstructed later
  narrow: window.matchMedia('(max-width: 1600px)').matches,
  coarse: window.matchMedia('(pointer: coarse)').matches
};
Enter fullscreen mode Exit fullscreen mode

The matchMedia lines record the decision itself, rather than leaving you to work backwards to it from a width. And if you keep only one field, keep innerWidth: a reporter who says 1920 and a page that says 1536 have told you, between them, everything you need to reproduce it, and neither of them had to understand why.

The ceiling on asking

Nearly every field in a bug report template is something the person can look up: browser, operating system, screen size, what they clicked. Zoom is an input to your layout that neither end can look up, because they do not know it and the page cannot read it back. The facts a template collects and the facts that decide a layout bug are not the same set, and the gap does not close by adding another question to the form.

Top comments (0)