Zoom and Reflow

🗺️

Home » Field Guide » Design » Zoom and Reflow

The Design Field Guide opens by naming three access questions. One of them is whether a layout still works at 200% zoom. This is the page that answers it.

We use zoom ourselves, on our own site, and had never hit a problem with it. That turned out not to mean what we assumed it meant. When we finally sat down and measured properly, we found two real failures — and the reason casual use had never surfaced them is instructive. One only appears on a page type we rarely zoom into. The other produces no symptom at all.

The test

Zoom is not a niche setting. It is one of the most common access adjustments there is — used by people with low vision, by people whose eyes are tired, by anyone reading a dense page on a bad day, and by a great many people who have simply pressed Cmd + so often they no longer think of it as an accommodation.

The standard is WCAG 1.4.10 Reflow, and it is stricter than it sounds. Content must reflow into a 320 CSS pixel wide column without forcing the reader to scroll in two directions at once. 320 px is not a phone-sized nicety — it is what a 1280 px desktop window becomes at 400% zoom. If a page passes at 320, it passes at every zoom level below it.

Two-dimensional scrolling is the failure. Scrolling down is reading. Scrolling down and right, line after line, is not reading — it is operating machinery.

What we found when we tested

We loaded our own pages at 320 px and measured. Three results, and they are not the same result.

Pages of ordinary prose pass cleanly. The Design Field Guide index reflowed to 320 px with zero horizontal overflow. Our layout, our type scale, and our lily pads all do what they should. That is the base case and it is fine.

Pages with code blocks failed. The Reading Experience notes produced 76 pixels of real horizontal scrolling at 320 px. Sixteen of its nineteen code blocks are rendered through a CodeMirror-based syntax highlighter, and every one of those sixteen was wider than the viewport. The three code blocks not run through the highlighter fit perfectly at 296 px — which is how we knew the highlighter, and not the code, was the problem.

This one is now fixed. One rule in Additional CSS —

.wp-block-code { overflow-x: auto; }

— takes that page from 76 px of two-directional scrolling to zero, at 320 px and at 1280 px alike. Every code block still scrolls internally to its full width, so nothing became unreachable in the process. That last check matters more than the first: a fix that stops the page scrolling by hiding the code would be worse than the bug.

Pages with third-party embeds clip. On our monotropism page there is no horizontal scrolling at all — instead the overflow is silently cut off. An Instagram embed carries min-width: 326px and runs 32 px past the edge. Two TikTok embeds carry min-width: 325px and run 17 px past. A 320 px viewport is the target; they are hard-coded to need more. You cannot scroll to the missing part. It is simply gone.

Three pages, three different failure modes, one of them invisible.

The measurement lesson

Here is the part worth carrying to any site, not just ours.

When we first measured the Reading Experience page, the browser reported a document scrollWidth of 1,356 px against a 320 px viewport — an apparent 1,036 px of overflow. Alarming, and wrong. When we then asked the page to actually scroll right as a reader would, it moved 76 px and stopped.

The DOM number was overstating the problem by a factor of thirteen, because content inside a scrollable container reports its full width whether or not the reader can ever reach it. Had we published the first number we would have been loudly, confidently incorrect about our own site.

Measure what the reader can do, not what the document reports. Scroll the page and see how far it goes. Then look for content sitting past the edge that cannot be scrolled to, because clipped content produces no number at all and is the worse failure of the two.

What we do

  • 320 px is the target, not 375. Test at the standard, not at the width of a current phone.
  • Test by zooming, not only by resizing. They are not identical: zoom scales text and layout together and interacts with the reader’s own default font size.
  • No fixed pixel widths on content containers. Percentages, max-width, and intrinsic sizing reflow; a hard width: 700px does not.
  • Anything that cannot wrap gets its own scroll container. Code, wide tables, and diagrams should scroll inside themselves with overflow-x: auto, so the page never scrolls sideways as a whole.
  • Fix the overflow without touching the width. Our first version of the code-block rule also set max-width: 100%, which looked harmless and was not. The theme centres content in its column with .is-layout-constrained > :where(…) { max-width: var(--wp--style--global--content-size); margin-inline: auto }, and :where() carries no specificity — so our max-width won, the 650 px column constraint vanished, and every code block on the site went full-bleed and left-aligned out of the text column. Reflow fixed, layout broken. overflow-x alone does the job.
  • Check for clipping, not just scrolling. A page with no horizontal scrollbar can still be hiding content past its right edge.
  • Structural basics stay correct. Our <meta viewport> is width=device-width, initial-scale=1 with no user-scalable=no and no maximum-scale — pinch-zoom is never disabled. That is a floor, and disabling it is one of the more contemptuous things a site can do.

What we do not fully control

Two of the three failures above are not ours to fix directly, and saying so is not an excuse — it is the actual shape of the problem.

Embedded third-party content ships its own minimum widths. Instagram wants 326 px, TikTok wants 325 px. Both exceed the 320 px reflow target by a handful of pixels, and neither is negotiable from our stylesheet without overriding somebody else’s embed code.

We are keeping the embeds. Community voices posting on the platforms they actually use is not a nice-to-have here, and “stop embedding” would solve a five-pixel layout problem by removing people from the page. The fix will be technical, and we have not yet worked out which technical fix is right.

Plugin chrome sizes itself independently. A cookie banner and a hidden search overlay each lay out wider than the viewport regardless of what our theme says.

The connection back to Controls That Defer is exact: a layer we did not write, sitting on top of the page, ignoring the conditions the reader has set. It is the same failure shape as an overlay, arriving through a different door.

Where this stands

  • Code blocks: fixed. One rule in Additional CSS, verified at 320 px and 1280 px, with every block still scrollable to its full content.
  • Embeds: open. The embeds stay. The remaining question is only how to contain them — override the third-party minimum widths, or wrap each embed in its own scroll container. Each has costs we have not weighed properly yet, and picking the wrong one quietly breaks somebody’s video. This is the next thing on this page’s list.
  • The rest of the site is untested. We checked three pages. There are 655.
  • This page is about zoom only. Focus indicators, touch target sizes, and keyboard traps are all required and all currently undocumented here. They are not covered by anything above, and saying “we tested zoom” is not the same as saying we tested access.

We would rather publish the failing numbers than a page claiming we pass. A guide that only describes the parts that already work is marketing.