Skip to content

Typography Scale

The fixed set of text sizes a product is allowed to use, and the line heights and weights that travel with each one.

Deliverables & Artifacts

A typography scale is the fixed set of text sizes a product may use. Everything outside the set is off limits, which is the point.

Without one, sizes accumulate: a 15px that appeared because 14 looked small in one card, a 17px from a design that was never reconciled, a 13px from a component library nobody adjusted. Audits of mature products routinely surface twenty or more distinct sizes, most of them within a pixel of another.

How many

Six to nine for most products.

Fewer forces compromises in dense interfaces, where a table cell, a label, and a caption genuinely need different treatments. More means adjacent sizes are indistinguishable, and a scale that nobody can perceive is not constraining anything.

A practical test: can a designer name every size from memory? If not, the scale is decoration.

Generating it

A modular scale multiplies a base by a fixed ratio. 16px at 1.25 gives 20, 25, 31.25, 39.06.

The relationships are even and the numbers are unusable, so most teams generate with a ratio and then round to whole values that sit on the spacing scale. The ratio informs the scale; it does not dictate it.

Large sizes want a bigger jump. The difference between 14 and 16 is visible; between 48 and 50 it is not. Scales that apply one ratio throughout end up with display sizes that cluster.

Each size carries more than a size

A number alone is half a decision, and the improvised half is what breaks vertical rhythm.

Line height. Tighter for large text, looser for body. A 48px heading at 1.5 has the spacing of a paragraph; 1.1 to 1.2 is the usual range for display and 1.5 to 1.6 for reading.

Weight. Which weights are available at this size. Light weights at small sizes fail contrast in practice even when the colour values pass.

Letter spacing. Negative for large display text, slightly positive for small caps and labels.

Bundle these into one token per role rather than three separate scales that have to be recombined correctly every time.

Name by role, not by size

font-size-16 tells somebody the value and nothing about when to use it. text-body, text-caption, text-heading-md tells them where it belongs, and survives the day the body size changes to 17.

Roles also make the scale enforceable. A component that asks for text-body cannot drift; a component that asks for 16 can become 15 in one branch.

rem, not px

Use rem so text respects the browser font size somebody has set. Hardcoded pixels override that preference for everybody who changed it, and that group is larger than most teams assume.

This is one of the cheapest accessibility corrections available. It is a find and replace, not a redesign.

In practice

A product audit finds twenty-three distinct font sizes across the application. Eleven fall between 13 and 17 pixels.

Consolidating to seven roles, the mapping is mostly mechanical: everything from 13 to 14 becomes text-caption, 15 to 17 becomes text-body. Two cases genuinely needed something the scale did not have, and the scale gained one size rather than pretending otherwise.

The visible change is small. What changed is that the next new screen has seven options instead of twenty-three, and none of them require a judgement call about whether 15 or 16 is right here.

Where teams get it wrong

  • Sizes without line heights. The rhythm improvised per screen.
  • A pure ratio, unrounded. 25.63px, forever.
  • One ratio across display and body. Large sizes that cluster.
  • Naming by value. A scale that cannot survive a base change.
  • Hardcoded pixels. A browser preference silently overridden.
  • Twelve sizes. No constraint, more decisions.

Frequently Asked Questions