Skip to content
ExamsLibraryFor agentsConnect your agent
typographyTypography·5/6

Type scale and rhythm

Every size comes from a closed scale named by role. Leading unitless — ~1.1 display, 1.5–1.6 body. Tracking follows size. woff2 only, font-synthesis none, high-level properties over raw tags, tabular figures on anything that updates.

Raw markdown On GitHub

Size, leading, and tracking carry more of typography's quality than any flourish; get the three right and most text problems never appear. This node is the mechanics beneath typography-humanity (which face) and beside line-length-tracking (how lines run).

Files and features

  • Ship woff2 and nothing else. Brotli-compressed and universally supported; ttf/otf in public/fonts is a bug. Load only the weights you use and subset to the characters you use.
  • font-synthesis: none at the root. Ask for an unloaded bold or italic and the browser fakes one by thickening or slanting glyphs. Turn it off so a missing file fails visibly.
  • High-level property over raw tag. font-weight: 620, not font-variation-settings: "wght" 620; font-optical-sizing: auto, not a hand-set "opsz"; font-variant-numeric: tabular-nums, not "tnum" 1. Properties still do something sensible on a fallback font; raw tags silently stop. Reserve font-variation-settings / font-feature-settings for custom axes and numbered stylistic sets, and comment what the numbered slot does in this font.
  • Tabular figures on anything that updates. Timers, prices, counters nudge their neighbours on every tick without them. The full feature and axis inventory is opentype-features-and-axes.
  • Light weights are size-bound. A 300 weight that looks elegant at 32px is illegible at 11px; keep light weights for display sizes. Size and baseline-shift footnote markers yourself, since the default <sup> is too big and pushes the line apart.

Build a scale, then obey it

A short closed list of sizes; departures need justification. Ratio-derived (1.2 on a 16px root) or Tailwind's stock steps are both fine. On a team, name steps by role — text-caption, text-card-title — because a role polices its own usage in a way text-lg cannot. Sizes in rem so the reader's settings hold; px is for hairlines, not text.

Leading follows role

Body 1.5–1.6; display and headings around 1.1 (large sizes carry their own optical spacing). Always unitless: line-height: 24px detonates on the first size tweak or user zoom. Paragraph spacing ≈ 1× line-height, not an arbitrary px.

Tracking follows size

Display sizes slightly negative (≈ −0.015em); small uppercase labels slightly positive (≈ +0.06em) so capitals get daylight; body zero. Track in em so it scales with the text. Kerning is the font's own pair data and stays on; font-kerning: none is a deliberate, rare act.

Crop the built-in space

Every font reserves headroom above the cap height and legroom below the baseline, which is why a label never sits dead-centre in its button. text-box: trim-both cap alphabetic crops it. Ship as progressive enhancement; the layout must survive where the trim never happens.

Display on a marketing page

On 202 measured gallery sites the hero headline runs a median 72 px (5.0 vw; middle half 43–109 px; 40 px on a phone), at leading ~1.0, about 4.3× body (4.7× on top-scored sites). The largest type is 8.4 vw on top-scored sites against 5.0 vw on weak ones. Size alone separates them, and weight doesn't have to: 48 % of heroes are regular weight. Budget the words before the size. Characters per line ≈ line width ÷ (size × k), with k ≈ 0.40 condensed, 0.50 most faces, 0.58 wide or caps, so a two-line headline at 44 px on a 390 px phone holds about 32 characters (four to six words). Over that, cut words before shrinking type. Product UI never gets this scale (dashboard-tells).

Pairing and count

Two faces cover most products; three is the ceiling. Pair across categories (serif display over sans text), never within. Two lookalike grotesques read as a version-control accident. Weights and sizes obey the same economy: each exists to mark hierarchy, and stacking too many erases the distinctions they were meant to draw. Two families at the same font-size rarely look the same size — x-height decides — so re-tune sizes when swapping faces and match the fallback stack's x-height to avoid a jolt on load.

When to apply

Setting up a project's type; any "text feels cramped here, airy there" complaint (one-off sizes are the cause); any live number; any font-loading diff.

Gotcha

Never change font weight on hover or selection. The text reflows by a pixel and the layout shifts. Hold weight constant and signal state with color; if emphasis must move, use a variable axis at the same advance width.

Sources

  • Emil Kowalski's design-engineering practice on typography, distilled by HKTITAN.
  • CSS Fonts Level 4 (font-synthesis, font-optical-sizing), CSS Inline Layout (text-box).
  • Leonxlnx, taste-skill v2.1.1 (MIT, HEAD a9c73c3): skills/taste-skill/references/type.md (202 sites measured at 1440 × 900 and 390 × 844, 2026-10-05; top and weak are model-panel tiers) and references/copy.md §2 (the headline budget; k values are its rule of thumb).
  • Related: typography-humanity, line-length-tracking, line-behavior, opentype-features-and-axes.

typographyscaleleadingtrackingfonts