Skip to content
All posts

Font size, line height, letter spacing — the typography triangle

Three CSS properties that change together: getting one right means tuning the other two. The numbers that work, and why.

DDDesign DeskDesign & Color EditorPublished May 14, 20265 min readbeginner

# The three knobs

Web typography is mostly three properties: font-size, line-height, letter-spacing. Plus a hidden fourth — the line length in characters per line. All four interact. Adjust one and you usually have to adjust at least one of the others.

The mistake is tuning them in isolation. The trick is recognising that they're a system.

# The defaults that mostly work


body {
  font-size: 1rem;        /* 16 px */
  line-height: 1.5;        /* unitless! */
  letter-spacing: 0;       /* leave it alone */
  max-width: 65ch;         /* enforces line length */
}

That's the boring, correct, never-fired-for default. About 95 % of long-form body text on the web should start here.

Why each:

  • 16 px is the browser default and roughly the minimum for comfortable reading. Below 14px on a typical desktop monitor and people squint. Below 12px, accessibility regulations start to call you out.
  • 1.5 unitless line-height puts the next line of text 24px below the current line, just enough breathing room for the eye to track without losing rhythm.
  • 0 letter-spacing because the font designer has already tuned the kerning. Override it and you fight the font.
  • 65ch max-width caps line length at roughly 65 characters (the "ch" unit is the width of "0" in the current font) — which lands in the comfortable 45-75 range across font choices.

The font-size calculator, line-height calculator, and letter-spacing calculator on AnytimeConvert each let you preview these in isolation.

# When to break the defaults

# Headlines: bigger means tighter

At display sizes (48px+), the same line-height that worked for body looks too loose. Drop it.


h1 {
  font-size: 3rem;         /* 48 px */
  line-height: 1.1;        /* not 1.5 */
  letter-spacing: -0.02em; /* slight tightening */
}

The negative letter-spacing closes up the gaps that look fine on body text but feel like potholes between giant letters. Almost every "modern, refined" headline style on premium sites is this trick.

# All-caps: bigger means wider

Uppercase letters take up more horizontal space than lowercase. Set them flush with default tracking and they read as clenched.


.eyebrow {
  font-size: 0.75rem;        /* 12 px */
  text-transform: uppercase;
  letter-spacing: 0.08em;    /* ~+1px of breathing room per letter */
  font-weight: 600;
}

The 0.08em positive tracking is the difference between "CRAMPED" and "SPACED OUT" — both literal renderings of the same string.

# Code blocks: monospace wants more line-height

Monospaced fonts lack the x-height variation that gives proportional fonts their visual rhythm. Code at the same line-height as prose feels squashed.


pre, code {
  font-family: monospace;
  line-height: 1.65;       /* not 1.5 */
}

The extra 10 % gives consecutive lines of code visual separation, especially when scanning for variable names.

# UI labels: smaller means tighter

Form labels, button text, navigation — none of these are read like body text. They're glanced at. Tighten the line-height so the UI doesn't feel sparse.


button, label, .nav-link {
  line-height: 1.25;       /* not 1.5 */
}

# The character-count rule

The most underrated typography property is line length, and CSS doesn't have a direct property for it — you control it with max-width on the text container.

The research is consistent: 45-75 characters per line is the comfort range. Below 45, the eye jumps too often and loses rhythm. Above 75, the eye loses its place on the line wrap.

The ch unit is purpose-built for this: 1ch = the width of "0" in the current font. So:


article p {
  max-width: 65ch;
}

…produces ~65 characters per line at most font choices, and self-adjusts when the font changes. Add this single line to any text-heavy page and reading speed measurably improves. (Measure it with a stopwatch — non-trivial readers complete pages 10-20 % faster with a comfortable line length.)

# A worked tune

You're laying out an article. Body text is fine at the default 16px / 1.5 / 0. The H1 looks loose at 48px. The eyebrow above the H1 looks cramped. Code blocks feel squashed.


body {
  font-size: 1rem;
  line-height: 1.5;
}
article {
  max-width: 65ch;
  margin-inline: auto;
}
h1 {
  font-size: 3rem;
  line-height: 1.1;
  letter-spacing: -0.02em;
}
.eyebrow {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
pre, code {
  line-height: 1.65;
}

Eight properties. The whole article now reads correctly across desktop, tablet, and phone, with no media queries.

# The traps

  • Don't use px for line-height. Use unitless. line-height: 24px on body text means the H1 inherits 24px line height, smaller than its own 48px font — the descenders crash into the next line.
  • Don't use the same line-height for every font size. A 12px caption and a 48px headline need different ratios; the headline tightens, the caption sometimes loosens.
  • Don't track body text. Override letter-spacing only on headlines, all-caps, and code. Body text is already kerned correctly.
  • Don't ignore line length. Without a max-width, body text on a 27" monitor wraps at 200+ characters per line. That's unreadable, no matter how good the font choice.

# Bottom line

Font size, line height, letter spacing, and line length are a coupled system. Tune them as a set, not in isolation. Start from sensible defaults (16px / 1.5 / 0 / 65ch), break them only when you can name why — headline display, all-caps eyebrow, UI label, code block — and the typography stops fighting you.

Common questions

Frequently asked.

What's the ideal line-height for body text?

1.5 is the safe default for 16-18 px body type. Slightly looser (1.6-1.7) for long-form reading; tighter (1.3-1.4) for UI text and labels where vertical space is constrained. Always use unitless values so the property inherits as the multiplier.

Should I add letter-spacing to body text?

No. Body fonts are kerned by their designers for body sizes; tracking them tighter or looser breaks the rhythm and reduces reading speed. Restrict letter-spacing changes to display sizes (negative, ~-0.02em on 48px+) and ALL CAPS (positive, +0.05-0.10em).

What's a comfortable line length?

45-75 characters per line, roughly. Below 45, your eye jumps too often. Above 75, you lose your place when wrapping. Set max-width on body text to ~35em (which gives ~65 characters at most font sizes) and it self-regulates.

New posts, once a week.

Practical developer guides. No spam. Unsubscribe any time.

Tools mentioned

Pick up where the post leaves off.

Keep reading

More from the field notes.