demo · v138

Typography scale test bench

Eight type-scale steps, a side-by-side card comparison, and a manual override slider to simulate the OS preference if your platform doesn't expose it yet. env(preferred-text-scale) defaults to 1 when the OS doesn't have an opinion — so this is one of those rare features where the right CSS is also the right fallback.

Available unflagged in Chrome 138 — but only meaningful on platforms that expose a font-scale preference (Android, ChromeOS, recent Windows / macOS). Use the slider below to simulate other values.
probing env(preferred-text-scale)…
current value 1.00×

Type ramp · all sizes × env(preferred-text-scale)

display
The quick brown fox
h1
Chrome 138 ships a missing primitive
h2
Typography that respects the user
h3
Section heading
body
Body copy. The OS-level preferred-text-scale env() variable lets a site respect the user's accessibility setting without polyfilling detection through JavaScript or vh tricks.
meta
Posted 12 minutes ago · Filed under accessibility, css
small
Caption / footnote text. Even this should remain readable at all OS scales.

Cards: text only vs everything scaled

card-text-only — only font sizes scale

Cache sharing

Allow-listed pervasive resources can share cache across origins. Smaller downloads, no correctness regressions.

read more

card-everything — padding, icon, button all scale with --xc

Cache sharing

Allow-listed pervasive resources can share cache across origins. Smaller downloads, no correctness regressions.

read more

At 1.8×: the left card has cramped hit-targets — text is huge, button is the same. The right card keeps the entire layout proportional. The "proportional chrome" pattern is the practical thing to ship.

The CSS

:root {
  --tx: env(preferred-text-scale, 1);    /* defaults to 1 when OS doesn't expose */
}

h1     { font-size:  calc(2.2rem * var(--tx)); }
body   { font-size:  calc(1rem   * var(--tx)); }

/* the proportional-chrome trick: multiply hit-targets and padding by the same factor */
button {
  padding: calc(0.55rem * var(--tx)) calc(0.9rem * var(--tx));
  font-size: calc(0.9rem * var(--tx));
}
.icon  { width:  calc(24px * var(--tx)); height: calc(24px * var(--tx)); }

What's happening

  1. env(preferred-text-scale, fallback) resolves to the user's OS-level font scale, or the fallback if unsupported / no opinion.
  2. Multiplying every font size by this single factor gives a site-wide ramp that respects accessibility without any media query rewriting.
  3. Multiplying everything — paddings, hit targets, icons — by the same factor gives "proportional chrome", which keeps the layout touch-friendly at large scales.
  4. Default value 1 means existing code paths are unchanged. This is one of the few APIs where adopting it costs nothing.

see also