Chrome has a font size setting. Settings, Appearance, Font size, with Medium at 16px, Large at 20px, Very Large at 24px, and a slider under "Customise fonts" that goes further. It is not zoom. Zoom scales pixels and rems together and keeps your layout intact. The font size setting changes the browser's default font size, which is a different thing, and it does something to a Tailwind site that we did not expect.

We measured our homepage and a guide page at four default font sizes in a window 1512 CSS pixels wide, which is a wide desktop window at every one of them.

The breakpoints move

sm = min-width: 40rem md = min-width: 48rem lg = min-width: 64rem xl = min-width: 80rem 

Those are Tailwind's defaults and they are what our markup is written against. In a media query, rem resolves against the browser's default font size, not against whatever :root computes to. So the pixel value of each breakpoint is the reader's setting multiplied by the number:

default font size sm matches md lg xl min-width: 1400px
16px yes yes yes yes yes
20px yes yes yes no yes
24px yes yes no no yes
32px yes no no no yes

The window never changed width. At a 32px default, md is asking for 1536 pixels, and a 1512 pixel window is not wide enough, so a desktop browser is served the layout we wrote for phones.

The last column is the interesting one. min-width: 1400px is the only media query on the whole site written in pixels. It comes from the container block in tailwind.config.ts, and it is the one breakpoint that stays exactly where we put it. Twelve rem breakpoints travel with the reader and one pixel breakpoint does not.

Which produces a heading that shrinks as the font grows

Our hero heading is:

<h1 className="text-4xl sm:text-5xl lg:text-6xl font-bold tracking-tight leading-[1.05]"> 

Measured on the live page:

default font size matched class rendered font-size
16px lg:text-6xl 60px
20px lg:text-6xl 75px
24px sm:text-5xl 72px
32px sm:text-5xl 96px

A reader who moves from Large to Very Large asks for bigger text and gets a hero heading three pixels smaller, because at 24px the window stopped being lg and the heading fell back a step. Every other piece of text on the page grew by half. Body copy went from 20px to 30px, the guide page's paragraphs from 18px to 27px, and the header from 57px tall to 85px.

It is a small thing and nobody will file a bug about it. It is also a clean demonstration that a rem breakpoint is a statement about the reader, not about the viewport, and we had been reading ours as if they were about the viewport.

At 32px the header loses its navigation entirely. The desktop nav is a single <nav className="hidden md:flex ..."> with no mobile counterpart, so when md stops matching, those four controls measure zero pixels wide:

control width at 16px width at 32px
PubTrivia wordmark 102px 171px
Features 58px 0
Solutions 62px 0
Pricing 46px 0
Resources 87px 0
Sign in 77px 148px
Get started 107px 203px

That is the same state a phone gets, where the footer carries the full navigation instead. It is a deliberate choice for narrow screens. It is an accident on a 1512 pixel window.

Then we ran the WCAG text spacing test

Different check, same shape of answer. Success criterion 1.4.12 says content must survive these four overrides:

* { line-height: 1.5 !important; letter-spacing: 0.12em !important; word-spacing: 0.16em !important; } p { margin-bottom: 2em !important; } 

Paste that into DevTools on any of our pages and watch for text that gets cut off. We looked for two things: elements with overflow: hidden whose content is now taller or wider than their box, and elements with text-overflow: ellipsis that are now actually truncating.

page clipped before clipped after truncated after document height
a guide 1 1 0 4,516 to 5,207
a comparison 1 1 0 3,827 to 4,312
the homepage 3 7 3 6,691 to 7,461

The single clipped element on the content pages before and after is the same one: a decorative wordmark in the footer that is hidden md:flex, aria-hidden, and deliberately cropped. It is not content. So those pages pass, and so do the other 66 built the same way.

Both tests fail on the same page, for the same reason

The homepage's failures all come out of one component: the animated product mock under the hero. It is built out of fixed geometry, because it is a picture of an application and applications have fixed-size chrome:

<div className="min-h-[540px] overflow-hidden">{children}</div> <div className="w-full aspect-video overflow-hidden">{children}</div> <span className="flex-1 truncate font-medium ...">{entry.name}</span> 

With text spacing applied, the aspect-video box holds 628 pixels of content in 575 pixels of space, and three truncate labels start ellipsising. At a 24px default font size the same box holds 761 in 673, the min-h-[540px] panel overflows by 14 pixels, and two labels ellipsise.

aspect-ratio plus overflow-hidden plus truncate is a reasonable way to build a mock and a guaranteed way to fail a text resize. The prose pages pass both tests without anybody having thought about either, because they are one column, no fixed heights, and no ellipsis anywhere.

The honest conclusion is not that we did accessibility work well on 67 pages. It is that single-column prose is robust by default and we only wrote fragile layout in the one place where we were drawing a picture of software.

Reproduce it

Two minutes, no account needed:

  1. Chrome, Settings, Appearance, Font size, Very Large. Open pub-trivia.app in a maximised window on a laptop display and watch the hero heading get smaller than it was at Large. Then drag the "Customise fonts" slider up and watch the header navigation vanish.
  2. Put it back to Medium, open DevTools on any guide, paste the four rules above into the Styles panel as a new stylesheet, and confirm nothing is cut off. Then do the same on the homepage and look at the mock.

The fix for the first one is to write the breakpoints we actually mean, which for a hero that should never shrink is a pixel width. The fix for the second is to let the mock scroll instead of clip. Neither is urgent. Both are the sort of thing you only find by changing a setting you have never changed.