Guides / Typography
text_fields

Web Typography Guide: Scales, Spacing & Readability

Typography is 95% of design. It determines readability, hierarchy, emotion, and brand voice. This guide covers the principles and CSS techniques that separate professional typographic systems from amateur ones.

April 2026 · 10 min read

The Typographic Scale

A typographic scale is a set of harmonically related font sizes. The modular scale (each step multiplied by a ratio) creates visual consistency across heading levels.

/* Modular scale with ratio 1.25 (Major Third) */
:root {
  --text-xs:   0.64rem;   /* 10.24px */
  --text-sm:   0.8rem;    /* 12.8px */
  --text-base: 1rem;      /* 16px */
  --text-lg:   1.25rem;   /* 20px */
  --text-xl:   1.563rem;  /* 25px */
  --text-2xl:  1.953rem;  /* 31px */
  --text-3xl:  2.441rem;  /* 39px */
  --text-4xl:  3.052rem;  /* 49px */
}

/* Usage */
h1 { font-size: var(--text-4xl); }
h2 { font-size: var(--text-3xl); }
h3 { font-size: var(--text-2xl); }
h4 { font-size: var(--text-xl); }
p  { font-size: var(--text-base); }
small { font-size: var(--text-sm); }

Fluid Typography with clamp()

clamp(min, preferred, max) creates type that scales smoothly between breakpoints without media queries. The preferred value uses viewport units for fluid scaling.

/* Fluid heading: 2rem on mobile → 4rem on desktop */
h1 {
  font-size: clamp(2rem, 4vw + 1rem, 4rem);
}

/* Fluid body text: 1rem → 1.125rem */
p {
  font-size: clamp(1rem, 0.5vw + 0.875rem, 1.125rem);
}

/*
  clamp() formula:
  - min: smallest size (mobile)
  - preferred: vw-based calculation for smooth scaling
  - max: largest size (desktop)

  Tip: use utopia.fyi to generate fluid type scales automatically
*/

/* Full fluid scale example */
:root {
  --step-0: clamp(1rem, 0.5vi + 0.875rem, 1.125rem);
  --step-1: clamp(1.25rem, 1vi + 1rem, 1.5rem);
  --step-2: clamp(1.5rem, 2vi + 1rem, 2rem);
  --step-3: clamp(2rem, 3vi + 1rem, 3rem);
  --step-4: clamp(2.5rem, 5vi + 1rem, 4rem);
}

Line Height: The Most Impactful Typography Setting

Line height (leading) has more impact on readability than font size. Too tight creates claustrophobia; too loose breaks the sense of grouping.

/* Line height ratios by context */
:root {
  --leading-tight:   1.2;  /* headings, large display type */
  --leading-snug:    1.35; /* subheadings, labels */
  --leading-normal:  1.5;  /* UI text, captions */
  --leading-relaxed: 1.65; /* body text, articles */
  --leading-loose:   1.8;  /* long-form reading, accessibility */
}

h1, h2 { line-height: var(--leading-tight); }
h3, h4 { line-height: var(--leading-snug); }
p      { line-height: var(--leading-relaxed); }

/* Rule of thumb:
   - Headings (large text): 1.1–1.3
   - Body text: 1.5–1.7
   - Small/caption text: 1.4–1.6 (needs more leading, not less)
*/

Measure: Optimal Line Length

Measure is the width of a column of text. The ideal is 45–75 characters per line. Too wide: eyes lose track of the next line. Too narrow: constant line breaks disrupt flow.

/* Using ch units (1ch = width of '0' character) */
article, .prose {
  max-width: 70ch; /* approximately 65-75 characters */
}

/* More precise with character count test:
   "The quick brown fox jumps over the lazy dog" = 44 chars
   Adjust max-width until a typical paragraph line is 50-70 chars
*/

/* For multiple column sizes */
.caption { max-width: 45ch; }
.body    { max-width: 70ch; }
.lead    { max-width: 55ch; }

Letter Spacing (Tracking)

Default letter spacing works for body text. Adjust for specific contexts: uppercase labels need positive tracking; large display headings often benefit from negative tracking.

/* Context-appropriate letter spacing */
/* All-caps labels, buttons, overlines */
.label, .overline, .badge {
  text-transform: uppercase;
  letter-spacing: 0.05em;  /* 0.05–0.1em for uppercase */
  font-size: 0.75rem;
}

/* Display headings (tighten at large sizes) */
.display-xl {
  font-size: clamp(3rem, 6vw, 6rem);
  letter-spacing: -0.02em; /* tighter at large sizes */
}

/* Body text */
p {
  letter-spacing: 0; /* or 0.01em for optical correction */
}

/* Never: tracking sans-serif body text positively
   Only tracking all-caps or small type positively */

Font Pairing Archetypes

Pairing TypeHeadingBodyCharacter
Classic editorialPlayfair DisplaySource Serif 4Authoritative, literary
Modern techInterInterClean, neutral, readable
Warm humanistLoraSource Sans 3Approachable, editorial
High contrastMontserratMerriweatherStrong, magazine-like
Minimal UIDM SansDM SansSystemic, app-like

Common Typography Mistakes

  • Body text below 16px — 16px is the minimum comfortable reading size. 17–18px is better for long-form content.
  • Using heading font for body text — display/heading fonts are designed for large sizes. At small sizes they lose legibility. Use a text-optimized typeface for body.
  • 100% line-height on body text — this makes lines collide. Always set line-height explicitly; browser defaults vary.
  • Positive letter-spacing on lowercase body text — spacing is set by the type designer for lowercase text. Expanding it hurts readability; only expand tracking on uppercase.
  • Using more than 2–3 typefaces — every additional font family adds cognitive noise and network overhead. 1 family (with multiple weights) or 2 families is almost always enough.

Frequently Asked Questions

What is the best font size for body text?
16px is the conventional baseline. For long-form reading (articles, documentation), 17–18px with 1.6–1.7 line-height is more comfortable, especially on large screens.
Should I use rem or px for font sizes?
rem (root em) respects the user's browser font-size preferences — important for accessibility. Users who've set their browser default to 20px because they need larger text will have that preference respected with rem but not with px.
How do I choose a font pairing?
The most reliable approach: pair a geometric/grotesque sans-serif with a humanist serif from the same period, or use a single superfamily with both display and text cuts (like Inter, Merriweather, or Source). Contrast in style (sans + serif) is safer than matching two different sans-serifs.
What is a variable font and should I use one?
A variable font contains an entire type family (weights, widths, optical sizes) in a single file. One file replaces 4–8 separate font files, with significant bandwidth savings. All major Google Fonts support variable fonts now — use them.