Skip to main content

Type Scales & Hierarchy

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:

RatioNameValue
Minor Second1.067Subtle, tight scale
Major Second1.125Gentle progression
Minor Third1.200Balanced, popular choice
Major Third1.250Clear contrast
Perfect Fourth1.333Strong contrast
Golden Ratio1.618Dramatic 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  h1

Implementing 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.