Why typography accessibility is the hard problem
Color contrast gets the most attention because contrast checkers are everywhere. Typography accessibility is the harder problem precisely because no single tool covers it. WCAG splits it across five separate Success Criteria — 1.4.4 (resize), 1.4.8 (visual presentation), 1.4.12 (text spacing), 1.4.3 (contrast), 1.3.1 (info and relationships) — and most teams audit one or two of them and ship.
Real typography accessibility is the sum of body size, line-height, line length, letter-spacing, paragraph spacing, font choice, heading hierarchy, and the contrast of every text role against every background it can land on — graded under both WCAG 2.2 and the APCA draft, evaluated against the text-spacing overrides that 1.4.12 mandates, and delivered as design tokens so the choices survive past the PR that introduced them.
The modular scale and the ratios that matter
A modular scale is just base × ratio^step. Pick a base (typically 16px for the body), pick a ratio (1.125 to 1.618), and every size in the system falls out of that one equation. The Studio supports eight ratios derived from musical intervals — minor second (1.067) at the subtle end through golden ratio (1.618) at the dramatic end.
| Ratio | Name | Best for |
|---|---|---|
| 1.067 | Minor second | Dense SaaS dashboards |
| 1.125 | Major second | Calm product UI |
| 1.2 | Minor third | Versatile default |
| 1.25 | Major third | Confident hierarchy |
| 1.333 | Perfect fourth | Marketing landing pages |
| 1.414 | Augmented fourth | Dramatic display |
| 1.5 | Perfect fifth | Editorial long-form |
| 1.618 | Golden ratio | Display-driven sites |
Stick to one ratio across the whole system. Mixing ratios is the design equivalent of switching key signatures mid-song — it works in jazz but it doesn't work in a design system.
Fluid sizing with clamp() — no media queries required
Each font size wraps in clamp(min, preferred, max) where preferred is a viewport-linear expression like 1.5rem + 1.2vw. Below the minimum viewport the size locks to min; above the maximum it locks to max; in between it interpolates smoothly.
The math, written out: slope = (maxPx − minPx) / (maxVw − minVw); intercept = minPx − slope × minVw; the resulting CSS is clamp(minPx, intercept + slope × 100vw, maxPx). No media queries, no breakpoint logic, just a smooth ramp from 360px screens to 1280px screens.
Body text usually stays constant — the readable size is the readable size whether the viewport is small or large. Headings benefit most from fluid sizing: an h1 that's 56px on desktop can comfortably shrink to 32px on a 360px phone without breaking the line at an awkward word.
WCAG 1.4.12 — the override test almost no one runs
WCAG 2.1 introduced Success Criterion 1.4.12 (Text Spacing, level AA) and WCAG 2.2 carried it forward. The requirement: users must be able to apply text-spacing overrides without losing functionality. Specifically:
line-height ≥ 1.5×Line height at least 1.5 times the font sizeletter-spacing ≥ 0.12emSpacing following letters at least 0.12 times the font sizeword-spacing ≥ 0.16emSpacing following words at least 0.16 times the font sizeparagraph-spacing ≥ 2×Spacing following paragraphs at least 2 times the font size
This is one of the most-failed criteria in WCAG 2.1 audits. Most production sites have some component — a fixed card height, a hardcoded button padding, a header bar with a baked-in font-size — that breaks when these overrides apply. The Studio's override toggle simulates the worst case so you catch it before users do.
Dyslexia, cognitive load, and the research that matters
The British Dyslexia Association style guide and the W3C Cognitive Accessibility Task Force converge on similar recommendations: larger body text (18px+), looser line-height (1.5+), generous letter and word spacing, shorter line length (≤ 60ch), sans-serif typefaces with distinctive letterforms.
Two typefaces deserve specific mention. Atkinson Hyperlegible, released by the Braille Institute in 2020, is specifically designed to maximize letterform distinction for low-vision readers — the b and d are unmistakable, the zero is dotted, the lowercase l carries an unmistakable curl. Lexend, designed by Bonnie Shaver-Troup with cognitive scientists, demonstrably improves reading speed in research trials, particularly for readers with dyslexia.
OpenDyslexic targets dyslexic readers specifically with weighted letterforms that anchor characters to the baseline. Research on its effectiveness is mixed — some readers benefit significantly, others see no improvement or prefer Atkinson. Offer it as an option rather than mandating it.
Readability scoring and the words themselves
Type design only goes so far. The words themselves matter. Two metrics are worth tracking on every page of significant body copy:
- Flesch Reading Ease (Rudolf Flesch, 1948):
206.835 − 1.015(words/sentences) − 84.6(syllables/words). Scores ≥ 60 are recommended for general audiences. 70+ is “fairly easy.” Below 50 most readers struggle. - Flesch-Kincaid Grade Level (1975):
0.39(words/sentences) + 11.8(syllables/words) − 15.59. Returns the approximate US school grade required to read the text. Aim for ≤ 8 in marketing copy, ≤ 10 in product docs, ≤ 12 for technical writing.
Both are imperfect. They miss vocabulary specificity, they reward short sentences regardless of quality, they don't understand cohesion. But they catch the easy failures: 35-word sentences, paragraphs of 3+ syllable words, copy written for executives and shipped to consumers.
Step-by-step workflow
Set the body first
Pick a base body size (typically 16px or 17px). Everything in the system derives from this. If the body is wrong, no amount of heading hierarchy will save you.
Choose a modular ratio
1.125 for subtle SaaS dashboards, 1.2 for general product UI, 1.25 as a versatile default, 1.333 for confident hierarchy, 1.5 for editorial, 1.618 for display-heavy marketing. Stick to one ratio across the whole system.
Wrap each stop in clamp() for fluid sizing
Define a min size (computed at the smallest viewport) and a max size (computed at the largest). The clamp() function linearly interpolates between them with no media queries. Body usually stays constant; headings shrink at narrow widths to avoid awkward line breaks.
Recommend line-height per role
Body 1.5–1.65, lead 1.4, h6 1.35, h5 1.3, h4 1.25, h3 1.2, h2 1.15, h1 1.1, display 1.05. Smaller sizes need looser leading; larger sizes get tighter as letterforms gain visual mass.
Pin line length between 45 and 80 characters
Set body max-width to roughly 65ch. Anything narrower forces too many returns; anything wider makes the eye lose track of the next line. WCAG 1.4.8 requires no more than 80 characters wide for body text.
Verify under the WCAG 1.4.12 override
Apply line-height ≥ 1.5×, letter-spacing ≥ 0.12em, word-spacing ≥ 0.16em, paragraph-spacing ≥ 2× the font size. The page must still work — nothing clipped, nothing overlapped, nothing inaccessible. This is the most-failed WCAG 2.1 criterion.
Grade contrast per role against the palette
Body text against page background and surface, large text against same, muted text against background, code against surface. Pass WCAG 1.4.3 for the legal floor and target APCA Lc ≥ 75 for fluent reading.
Run reading-level analysis on actual copy
Aim for Flesch Reading Ease ≥ 60 and Flesch-Kincaid Grade Level ≤ 8 for general audiences. Long sentences and 3+ syllable words are the two biggest drivers of unreadable copy.
Export tokens for every consumer
Tailwind v4 @theme, Tailwind v3 config, CSS variables with utility classes, W3C DTCG composite typography tokens, Tokens Studio JSON for Figma, Swift UIFont, Compose TextStyle. Single source of truth, every platform.
FAQ
What's the minimum body font size for accessibility?
16px is the practical minimum for body text on desktop. Below 14px, even good typefaces start failing for users with mild low vision. The Studio passes anything at or above 16px (after fluid clamp at the smallest viewport), warns between 14–16px, and fails below 14px. Compact data dashboards sometimes ship at 14px — that's defensible if the contrast and zoom support are otherwise excellent, but it's a stretch.
What is the WCAG 1.4.12 text-spacing override test?
WCAG Success Criterion 1.4.12 (Text Spacing, level AA) requires that pages still function correctly when users apply text-spacing overrides via their browser or assistive tech. The required minimums: line-height ≥ 1.5× font size, letter-spacing ≥ 0.12em, word-spacing ≥ 0.16em, paragraph-spacing ≥ 2× font size. The Studio's override toggle simulates these forced values so you can spot clipped text, overlapping elements, and cramped components before users complain.
Why does a modular scale matter for accessibility?
A modular scale produces a hierarchy where each size step is mathematically related to the next — base × ratio^n. The result feels coherent to users with cognitive disabilities (predictability), large-print needs (consistent stepping), and screen readers (heading levels match visual hierarchy). An arbitrary mix of 18px, 22px, 28px, 31px, 38px breaks the implicit promise of visual rhythm.
Which fonts are most accessible?
Atkinson Hyperlegible (Braille Institute, 2020) and Lexend (Bonnie Shaver-Troup, 2020) are designed specifically for accessibility — Atkinson maximizes letterform distinction for low-vision readers, Lexend reduces visual stress and improves reading proficiency in research trials. For general accessibility, modern sans-serifs like Inter, Geist, and IBM Plex Sans hold up well. OpenDyslexic specifically targets dyslexic readers with weighted letterforms; it works for some readers and not others.
What is fluid typography with clamp() and why use it?
Fluid typography wraps each size in CSS clamp(min, preferred, max) so the size interpolates linearly between a small and large viewport with no media queries. At 360px viewport you get the min size; at 1280px you get the max; everywhere in between is a smooth ramp. The math: clamp(min, intercept + slope × 100vw, max) where slope = (max−min)/(maxVw−minVw) × 100. Headings benefit most — shrinking h1 on small screens avoids ugly line breaks while keeping body text constant.
What is Flesch Reading Ease and how do I use it?
Flesch Reading Ease (Rudolf Flesch, 1948) scores text on a 0-100 scale based on average sentence length and average syllables per word. Higher is easier. 60-69 is “standard” (8th-9th grade). Marketing and product copy should aim for ≥ 60. Long-form content can go lower if the audience is technical. The Studio's analyzer pairs the score with Flesch-Kincaid Grade Level (US school grade equivalent) and flags long-sentence patterns.
How do I handle typography accessibility for users with dyslexia?
The British Dyslexia Association recommends: 18px+ body, generous line-height (≥ 1.5), looser letter-spacing (+0.03em or more), tighter line length (≤ 60ch), sans-serif typefaces with distinctive letterforms (Atkinson Hyperlegible, Lexend, or Open Sans). Avoid italics for long passages. Avoid all-caps. The Studio's “Dyslexia-friendly” preset applies all of this in one click.
Can I pair this with a color palette?
Yes — paste a palette's primary hex into the Studio (or share a URL between the Typography Studio and the Palette Studio) and the typography report grades each text role's contrast against the palette's derived background and surface tokens using both WCAG 2.2 ratios and APCA Lc. The two studios together produce a complete design-system-in-a-box.
How do I export typography tokens?
Same story as colors. Use W3C DTCG composite typography tokens as your source of truth; transform to Tailwind v4 @theme blocks, v3 config, CSS variables with utility classes, Tokens Studio JSON for Figma, Swift UIFont extensions, and Jetpack Compose TextStyle objects. The Studio outputs all of these in one click.
Build your typography system in the Studio
Apply every step of this guide in one click: modular type scale, fluid clamp() sizing, dyslexia / cognitive / low-vision presets, WCAG 1.4.12 override testing, per-role contrast grading, Flesch-Kincaid analyzer, and token exports for every platform.