Skip to content
@erikakers/typography

Roles

Eleven roles, derived rather than hand-picked, at the shipped configuration ($scale-base: 1rem, $scale-ratio: 1.25, $leading-base: 1.5).

Role Step Size Leading Tracking Measure Lead Flow
display 7 4.7684rem 1.1 -0.02254em 14ch 3rem 1.5rem
h1 6 3.8147rem 1.1 -0.01932em 17ch 3rem 0.75rem
h2 5 3.0518rem 1.135 -0.0161em 21ch 3rem 0.75rem
h3 4 2.4414rem 1.2 -0.01288em 27ch 3rem 0.75rem
h4 3 1.9531rem 1.269 -0.00966em 33ch 3rem 0.75rem
h5 2 1.5625rem 1.342 -0.00644em 42ch 3rem 0.75rem
h6 1 1.25rem 1.419 -0.00322em 52ch 3rem 0.75rem
lead 1 1.25rem 1.419 -0.00322em 52ch 0rem 1.5rem
body 0 1rem 1.5 0em 65ch 0rem 1.5rem
caption -1 0.8rem 1.5 0.00322em 80ch 0.75rem 1.5rem
fine -2 0.64rem 1.5 0.00644em 80ch 0.75rem 1.5rem
code 0 1rem 1.5 0em 65ch 0rem 1.5rem

Sizes: body at step 0, every heading above it. This makes “no heading collides with body text” true by construction at any ratio greater than 1. Below body there are two rungs and no more: caption at -1 and fine at -2 — the small-text layer under a caption (a nav link, an eyebrow, a table header, a byline). fine carries no kind of its own; it shares caption’s.

The scale stops at -2, and that is measured rather than chosen — nothing enforces it. The fluent range for continuous reading spans 0.2° to 2° of angular x-height; the bottom of that band works out to about 0.641rem at a 16px root, and at the shipped ratio step -2 sits just under it. It is stated rather than guarded, because the bound is angular and a CSS length only crosses it at an assumed viewing distance. Full derivation: docs/scale-floor.md.

Leading is derived from the size, clamped to [1.1, $leading-base]. Tracking is zero at body, tighter above it and looser below, from the log of the size ratio. Measure is derived from the size, not the ratio — size × measure held constant, clamped into the 13-80 character band.

code takes a line advance instead of a leading ratio. --type-advance-code is one rhythm unit, so an n-line code block is exactly n rhythm units tall.

The role vocabulary

Every field a role may declare, and what governs it.

Key Unit Required Notes
size root-relative yes rem, respects the reader’s font-size preference
leading unitless yes Inherits as a ratio; the script layer can multiply it
tracking em yes Tracks the size it is applied to
measure unitless yes A character count, validated against 13-80 on emit
weight keyword or 1-1000 yes CSS Fonts 4, or a $font-weights name
lead relative yes Space before the block. rem when derived
flow relative yes Space after the block. rem when derived
family font stack no code always; every role when $font-family-base is set
family-fallback font stack no The var() fallback behind it. code only
wrap text-wrap value no pretty on prose, balance above. Undeclared roles inherit
advance root-relative no A fixed line advance, used instead of leading. code only

size is held to a root-relative unit, narrower than relative(): the token is declared once on :root and read by every element the role reaches, so an em size would mean a different length at each nesting depth.