Why is sizing body text with font-size: 4vw an accessibility problem, and how does a clamp() with a rem term fix it?
answer
- what is vw measured against?
- nothing in its definition mentions the root
- the reader's own font-size setting
- text-only zoom does not touch it
- keep a rem term in the expression
basics
~20 sViewport units ignore the reader's browser font-size preference and text-only zoom, so 4vw text will not enlarge for someone who needs it bigger. Putting rem back into the value — clamp(1rem, 0.9rem + 1vw, 1.5rem) — restores that control while keeping the fluid behaviour.
solid answer
~50 s`vw` resolves purely against the viewport width, so it is deaf to the two controls readers actually use to make text bigger: raising the browser's default font size, and text-only zoom in browsers that offer it. A user who sets their default to 24px sees `rem`-based text grow and `4vw` text stay exactly where it was. Full-page zoom does still enlarge `vw` text, because zooming shrinks the layout viewport measured in CSS pixels — so this is a preference and text-zoom failure, not a total one, and saying that precisely matters. It puts WCAG 2.2 success criterion 1.4.4 Resize Text at risk. The fix is to keep a `rem` component in the value: `font-size: clamp(1rem, 0.9rem + 1vw, 1.5rem)`. The bounds are in `rem` so they track the root size, and the constant term in the preferred value means part of the fluid range moves with the reader's preference too.
go deeper
Know that rem is tied to the root font-size the reader can change, while vw is tied only to the viewport width, and that body text should never be sized in vw alone.
Explain the mechanics: vw's definition references nothing but the viewport, so raising the default font size moves rem text and leaves vw text untouched, and describe why a rem term inside clamp() restores the link.
Show the production judgment — cite WCAG 1.4.4 Resize Text, distinguish page zoom (which does scale vw) from font-size preference and text-only zoom (which do not), and check that containers can grow with the text you just made fluid.
Own it as policy rather than per-component vigilance: define the fluid scale once in rem-bounded tokens, forbid raw vw font sizes in review or lint, and make an enlarged-default-font-size pass part of the accessibility acceptance criteria.
## What vw is actually measured against `1vw` is one percent of the viewport width. That is its complete definition — no font, no root element, no user setting enters the calculation. `1rem` by contrast is the computed `font-size` of the root element, which by default is whatever the reader has configured as their browser's default font size. That single difference is the whole accessibility story. ## The two controls that break **Browser font-size preference.** Every major browser has a default-font-size setting, and readers with low vision routinely raise it from 16px to 20px, 24px or more. `rem`-based type responds immediately: `1rem` becomes 24px. `4vw` does not move by a pixel, because nothing in its definition refers to the root font size. A page whose body copy is `4vw` simply ignores a stated user preference. **Text-only zoom.** Some browsers offer a mode that scales text without scaling the layout. In that mode, viewport-relative text does not grow at all, while `rem` and `em` text does. **What does still work — say this part too.** Full-page zoom does enlarge `vw` text, because page zoom effectively shrinks the layout viewport measured in CSS pixels, so `4vw` resolves to more device pixels. A candidate who claims "`vw` text can never be zoomed" is overstating it and a good interviewer will notice. The accurate claim is narrower and stronger: `vw` sizing is unresponsive to the reader's font-size preference and to text-only zoom. ## The standard this maps to WCAG 2.2 success criterion **1.4.4 Resize Text** (level AA) requires that text can be resized up to 200% without assistive technology and without loss of content or function. Viewport-only text sizing is a common way to fail it, especially in combination with fixed-height containers that clip once text does grow. ## The two failure modes at the extremes Even setting user preference aside, unbounded `vw` type misbehaves at the ends of the range. On a 320px phone `4vw` is 12.8px — below any reasonable body-text floor. On a 2560px monitor it is 102px, which is comical for paragraph copy and destroys line length. Bounds are needed regardless of accessibility. ## The fix, and why each part matters ```css body { font-size: clamp(1rem, 0.9rem + 1vw, 1.5rem); } ``` - **Floor in `rem`.** `1rem` scales with the reader's root font-size, so the minimum size is a *relative* minimum, not a frozen pixel value. Writing `clamp(16px, ...)` would defeat the whole exercise. - **Ceiling in `rem`.** Same reasoning at the other end: `1.5rem` grows with the preference, whereas `32px` would cap a reader who wants larger text. - **A `rem` term inside the preferred value.** `0.9rem + 1vw` means most of the size comes from the root font-size and only a slice comes from the viewport. Raise the default font size and the fluid mid-range moves with it. A bare `4vw` preferred value, even with `rem` bounds, still ignores the preference everywhere between the bounds. A common shape is that the `rem` term supplies the majority of the value and the `vw` term the minority — the more `vw`-dominant the expression, the less the reader's preference matters. ## Related mistakes in the same family **Pixel bounds.** `clamp(16px, 2vw, 24px)` looks defensive but pins both ends against user preference. **Clamping too tightly.** If the floor and ceiling are close together, the value is effectively fixed and the fluidity is decorative. Worse, a very low ceiling can cap a reader who has asked for large text. **Fixed-height containers around fluid text.** Text that can grow needs a container that can grow. Enlarged text overflowing a `height`-constrained card is a loss-of-content failure even though the type itself scaled correctly. **Applying it to everything.** Fluid sizing on interactive-control text can shrink hit targets and labels below comfortable sizes on small screens; the `rem` floor is what protects them. ## How to answer it State the mechanism (`vw` is defined against the viewport, not the root font-size), name the two controls it ignores, concede honestly that page zoom still works, cite SC 1.4.4, then give the fixed declaration and explain why each `rem` in it is load-bearing.
- Does browser page zoom enlarge vw-sized text?Yes, and it is worth conceding precisely. Page zoom shrinks the layout viewport measured in CSS pixels, so `4vw` resolves to more device pixels and the text does get bigger. The failure is narrower: `vw` text ignores the browser's default-font-size preference and does not respond to text-only zoom modes. Overstating the problem as "vw text can never be zoomed" is inaccurate.
- Why should the clamp() bounds be written in rem rather than px?Because a px bound is frozen against the reader's root font-size. `clamp(16px, 2vw, 24px)` guarantees the text never exceeds 24px even for someone who set their default font size to 24px, so the ceiling actively fights the preference. `rem` bounds scale with the root, keeping the floor and ceiling relative constraints rather than absolute ones.
- How do you check that a fluid type scale actually survives a reader enlarging text?Change the browser's default font size — not page zoom — to something like 24px and reload, then walk the page at narrow and wide viewports. Look for text that did not move at all, for fixed-height containers now clipping their contents, and for ceilings that capped growth. Text-only zoom, where available, is the second pass.
saying these in an interview costs you the question
- Claiming vw text cannot be enlarged by any zoom at all
- Believing px bounds inside clamp() make the value accessible
- Saying viewport units respond to the browser's default font size
- Treating any clamp() as automatically accessible regardless of units
- Ignoring that enlarged text needs containers that can grow