Typography System & Type Scale
Modular type scales, line-height ratios, and responsive clamp() sizing for readable text everywhere.
Design TokensIntermediate
Why
Inconsistent type sizes (14px here, 13px there, 15px in modals) make a UI feel uncared-for and hurt readability. A modular scale from one ratio gives harmonious sizes that scale fluidly across viewports.
Tokens Studio (formerly Figma Tokens) has 500k+ installs, and the W3C Design Tokens Format Module is nearing candidate recommendation. Tokens enable dark mode, multi-brand theming, and platform parity from a single source.
When
Define the type scale before designing screens. If you have 8+ font sizes in use, audit and collapse them onto a scale — most products need only 5-7 sizes.
How
1. Pick a base — 16px (1rem) body, the browser default and most readable
2. Pick a ratio — 1.25 (major third) for dense UIs, 1.333 (perfect fourth) for editorial
3. Generate scale — base × ratio^n for -2..+4, round to rem with 2 decimals
4. Line-height — 1.5 for body, 1.25 for headings, 1.1 for display
5. Fluid sizing — clamp(min, preferred vw, max) so headings grow with viewport
6. Font loading — preload woff2, font-display: swap, subset to latin + cjk
7. Tokens — --font-size-{-2..4}, --line-height-{body|heading|display}
Example
// typography-tokens.css — modular scale (ratio 1.25, base 1rem)
:root {
--font-size--2: 0.64rem; /* 10px — caption */
--font-size--1: 0.80rem; /* 13px — small */
--font-size-0: 1.00rem; /* 16px — body */
--font-size-1: 1.25rem; /* 20px — h4 */
--font-size-2: 1.56rem; /* 25px — h3 */
--font-size-3: 1.95rem; /* 31px — h2 */
--font-size-4: 2.44rem; /* 39px — h1 */
--line-height-body: 1.5;
--line-height-heading: 1.25;
}
/* Fluid h1 — grows from 28px to 39px between 640px and 1024px viewport */
h1 {
font-size: clamp(1.75rem, 2vw + 1rem, var(--font-size-4));
line-height: var(--line-height-heading);
}
/* font loading — preload + swap to avoid FOIT */
/* <link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin> */
@font-face { font-family: "Inter"; src: url("/fonts/inter.woff2") format("woff2"); font-display: swap; }
Common Problems
- ⚠Too many sizes — 14 sizes in use, half differ by 1px, impossible to keep consistent
- ⚠Fixed px sizes — doesn't scale with user's browser font-size setting, breaks a11y
- ⚠FOIT on font load — invisible text for 3s while the web font downloads
Best Practices
- ✓Use rem not px — respects user font-size setting, required for WCAG 1.4.4 resize
- ✓Cap the scale at 7 sizes — if you need an 8th, your hierarchy is wrong, redesign
- ✓Always font-display: swap — show fallback text immediately, swap when font arrives