A Modular Typography Scale for the Web
Type sizes chosen one at a time rarely sit well together. A modular scale derives every size from one base and one ratio, so headings and body text feel like members of the same family.
Open a stylesheet that grew organically and you will find a typographic zoo: 14px, 15px, 18px, 21px, 22px, 28px, 30px — sizes added one at a time, each reasonable in isolation, none aware of the others. The result is text that never quite harmonizes. A modular type scale solves this by generating every size from a single base and a single ratio, so the whole hierarchy is related by design rather than by accident.
Why ad-hoc sizes feel wrong
Typographic hierarchy works through contrast: a heading reads as a heading because it is clearly larger than the body, not vaguely larger. When sizes are chosen independently, the contrast between levels becomes uneven — a big jump here, a barely-there difference there — and the eye struggles to build a clean mental map of what is important. Inconsistent steps read as indecision.
There is also a compounding cost. Each new size is one more value to remember, to apply consistently, and to maintain. A page with nine subtly different font sizes is harder to keep coherent than one with five clearly distinct ones, and the extra four sizes almost never earn their keep.
What a modular scale is
A modular scale starts with a base size — usually the body text, often 16px — and a ratio. Each step up multiplies by the ratio; each step down divides by it. Choose a base of 16 and a ratio of 1.25, and the scale climbs 16, 20, 25, 31, 39, and so on. Every size is mathematically related to every other, which is exactly why they look related on the page.
:root {
--text-base: 1rem; /* 16px */
--text-lg: 1.25rem; /* 20px */
--text-xl: 1.5625rem; /* ~25px */
--text-2xl: 1.953rem; /* ~31px */
--text-3xl: 2.441rem; /* ~39px */
--text-sm: 0.8rem; /* 16 / 1.25 */
}Rounding matters in practice — sub-pixel font sizes are fine for the browser but awkward to talk about, so most teams round to sensible values and keep the relationship close rather than exact. The point is not mathematical purity; it is that the sizes share a common origin and therefore a common feel.
Choosing a ratio
The ratio sets the personality of the scale. A small ratio like 1.125 produces gentle, closely-spaced steps that suit dense, information-rich interfaces where you cannot afford huge headings. A large ratio like 1.5 produces dramatic contrast that suits editorial or marketing pages where a headline should command the screen. Most product UIs live comfortably between 1.2 and 1.333.
- Smaller ratios (1.125–1.2): compact, utilitarian, good for dashboards and dense apps.
- Medium ratios (1.25–1.333): balanced, the safe default for most product interfaces.
- Larger ratios (1.4–1.6): expressive, suited to landing pages and long-form reading.
There is no universally correct ratio, only one that fits the work. The discipline is to choose one and let it govern the whole scale, rather than reaching for a different relationship every time a new heading level is needed.
Line height and measure
Size is only half of readable type; the space around the letters matters just as much. Line height should generally loosen as text gets smaller and longer — body copy reads best with generous leading, around 1.5 to 1.7, while large headings can sit much tighter because each line is short and the size carries it. A single line height applied to every size is a common and avoidable mistake.
Measure — the length of a line of text — is the quietest of the three and the most often ignored. Lines that run too long make the eye lose its place returning to the start; lines too short chop the rhythm of reading. A comfortable measure for body text is roughly 60 to 75 characters, and constraining it is one of the cheapest ways to make long text feel professional.
Good typography is not about the fonts you choose. It is about the relationships between sizes, spacing, and line length.
Responsive type
A scale tuned for a wide screen can feel oversized on a phone, where a 39px heading eats the whole viewport. The simplest approach is to shift the base size or the ratio at a breakpoint or two, so the scale recomposes itself for smaller screens. Fluid techniques can interpolate sizes smoothly between breakpoints, but even a couple of deliberate steps are far better than a single fixed scale stretched across every device.
Whatever the method, keep the relationships intact. Responsive type should rescale the whole family together so the hierarchy survives; it should not flatten the contrast between heading and body just because the screen got smaller. The hierarchy is the point, and it must hold at every width.
Limiting the scale
A scale can generate infinite sizes, but a product should expose only a handful. Pick the five or six steps the interface actually needs — say, a body size, two smaller, and three larger — and treat the rest as theoretical. Fewer published sizes means a hierarchy that is easier to apply consistently and far easier to keep coherent as the product grows.
Expose the chosen steps as tokens or utility classes named by role rather than by pixel value — text-body, text-heading, text-caption — so the names survive a future retuning of the scale. As with spacing and color, the indirection is what lets the underlying values change without a rename cascade through the codebase.
Putting it to work
Pick a base, pick a ratio, generate a handful of steps, and pair each with a sensible line height. Round the numbers, name them by role, and resist adding a new size every time something looks slightly off — usually the fix is choosing an existing step, not inventing another. Do this once and your type stops being a collection of arbitrary numbers and starts behaving like a family that was always meant to be together.



