A type scale is a set of font sizes that relate to each other through a consistent ratio. Instead of picking arbitrary sizes like 13px, 17px, and 22px, a type scale ensures every size feels harmonious and intentional. Combined with proper hierarchy, a good type scale makes content scannable and easy to read.
What Is a Modular Scale?
A modular scale multiplies a base font size by a fixed ratio to generate each step. The most common ratios come from musical intervals and mathematical proportions:
| Ratio | Name | Value |
|---|---|---|
| Minor Second | 1.067 | Subtle, tight scale |
| Major Second | 1.125 | Gentle progression |
| Minor Third | 1.200 | Balanced, popular choice |
| Major Third | 1.250 | Clear contrast |
| Perfect Fourth | 1.333 | Strong contrast |
| Golden Ratio | 1.618 | Dramatic jumps |
Starting with a 16px base and a Major Third (1.250) ratio:
Step -1: 16 / 1.250 = 12.8px → small text
Step 0: 16px → body text
Step 1: 16 × 1.250 = 20px → large text
Step 2: 16 × 1.250² = 25px → h4
Step 3: 16 × 1.250³ = 31.25px → h3
Step 4: 16 × 1.250⁴ = 39.06px → h2
Step 5: 16 × 1.250⁵ = 48.83px → h1Implementing a Type Scale in CSS
Convert your scale to CSS custom properties for easy reuse:
:root {
--text-xs: 0.8rem; /* 12.8px */
--text-sm: 0.875rem; /* 14px */
--text-base: 1rem; /* 16px */
--text-lg: 1.25rem; /* 20px */
--text-xl: 1.563rem; /* 25px */
--text-2xl: 1.953rem; /* 31.25px */
--text-3xl: 2.441rem; /* 39.06px */
--text-4xl: 3.052rem; /* 48.83px */
}
body { font-size: var(--text-base); }
h1 { font-size: var(--text-4xl); }
h2 { font-size: var(--text-3xl); }
h3 { font-size: var(--text-2xl); }
h4 { font-size: var(--text-xl); }Use rem units so sizes scale with the user's browser font size preferences — an important accessibility consideration.
Heading Hierarchy
Headings create a visual outline of your content. Users scan headings to decide whether to read a section, so hierarchy must be clear and consistent.
Rules for heading hierarchy:
- One h1 per page — The h1 is the page title. Having multiple h1s confuses screen readers and dilutes the visual hierarchy.
- Never skip levels — Go from h2 to h3, not h2 to h4. Skipping levels breaks the semantic outline.
- Size difference matters — Each heading level should be noticeably different from the next. If h2 and h3 look nearly identical, the hierarchy fails.
- Weight adds contrast — Use bolder weights for higher-level headings. h1 might be 700 (bold), h3 might be 600 (semibold), and body text 400 (regular).
Line Height
Line height (leading) controls the vertical space between lines of text. It directly affects readability:
- Body text — 1.5 to 1.75 is ideal. This gives each line room to breathe without feeling disconnected.
- Headings — 1.1 to 1.3 works well. Headings have larger text, so they need less relative spacing.
- Captions and small text — 1.4 to 1.6 keeps small text readable.
body {
line-height: 1.6;
}
h1, h2, h3 {
line-height: 1.2;
}
.caption {
font-size: var(--text-xs);
line-height: 1.5;
}A common mistake is using the same line height for all text. Headlines with a 1.6 line height look disconnected and floaty, while body text with 1.2 line height feels cramped.
Letter Spacing
Letter spacing (tracking) is the uniform horizontal space between characters. Unlike kerning (which adjusts space between specific character pairs), tracking applies to all characters equally.
Guidelines:
- Body text — Leave at default (0). Typeface designers optimize letter spacing for body sizes.
- All-caps text — Add 0.05em to 0.1em. Uppercase letters sit close together by default and benefit from extra breathing room.
- Large headings — Slightly tighten (-0.01em to -0.02em). At large sizes, default spacing can look loose.
.uppercase-label {
text-transform: uppercase;
letter-spacing: 0.05em;
font-size: var(--text-xs);
font-weight: 600;
}
h1 {
letter-spacing: -0.02em;
}Responsive Typography
On mobile screens, your desktop type scale may be too aggressive — an h1 at 49px overwhelms a 375px-wide screen. Use CSS clamp() for fluid sizing:
h1 {
font-size: clamp(2rem, 5vw, 3.052rem);
}This sets a minimum of 2rem, scales with the viewport, and caps at 3.052rem. The text smoothly adjusts between breakpoints without media queries.