Text Spacing and Readability

โ–ถ Try It Yourself

Good typography is mostly invisible โ€” when text is well-spaced, readers absorb content without noticing the typesetting. But when line-height is too tight, measure too wide, or letter-spacing wrong, readers fatigue quickly. In this lesson you will master the CSS properties that control how text breathes: line-height, letter-spacing, word-spacing, text-indent, and the critical concept of measure (line length) โ€” the properties that separate professional typography from amateur work.

Text Spacing Properties

Property Controls Recommended Values
line-height Vertical space between lines of text 1.5โ€“1.75 for body; 1.1โ€“1.3 for headings
letter-spacing Horizontal space between individual characters -0.02em on headings; 0.05โ€“0.1em on uppercase labels
word-spacing Space between words Normal is usually ideal; use sparingly
text-indent First-line indentation of a paragraph 1โ€“2em for classic book indentation
max-width (measure) Maximum line length โ€” characters per line 60โ€“75 characters โ€” approx 45โ€“65ch

line-height Values Compared

Value Type Behaviour Recommendation
1.6 (unitless) Multiplier Scales with element font-size โœ… Best โ€” child elements inherit the ratio not a computed value
1.6em em Computed once; children inherit the px value โš ๏ธ Causes inheritance issues in nested elements
26px Fixed px Fixed regardless of font-size changes โŒ Breaks if font-size changes
normal Browser default ~1.2 in most browsers โŒ Too tight for body text

Typography Readability Guidelines

Element line-height letter-spacing Measure (ch)
Body paragraph 1.6โ€“1.75 0 (default) 55โ€“75ch
Large heading (h1) 1.05โ€“1.2 -0.02em to -0.04em 20โ€“30ch
Small heading (h3โ€“h4) 1.25โ€“1.4 -0.01em 35โ€“50ch
UI label / caption 1.4โ€“1.5 0.04โ€“0.1em (uppercase) N/A
Code / monospace 1.5โ€“1.7 0 (default) 80โ€“100ch
Note: Always use a unitless number for line-height (e.g. 1.6 not 1.6em or 26px). A unitless value is a multiplier โ€” children inherit the ratio and apply it to their own font-size. A px or em value is computed once and the fixed pixel result is inherited, causing cramped or excessively spaced child text.
Tip: The ch unit โ€” the width of the “0” character in the current font โ€” is ideal for controlling line length (measure). max-width: 65ch gives approximately 65 characters per line, which typographers recommend as the optimal reading measure for body text. It automatically adjusts when the font changes.
Warning: Negative letter-spacing on body text at small sizes makes text harder to read. Only use negative letter-spacing on large headings (24px+) where default tracking feels too loose. Adding positive letter-spacing to all-caps labels (letter-spacing: 0.08em) significantly improves readability for short uppercase strings.

Basic Example

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&family=Playfair+Display:wght@700&display=swap" rel="stylesheet">
  <title>Text Spacing and Readability</title>
  <style>
    html { font-size: 100%; }
    *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
    body { font-family: 'Inter', system-ui, sans-serif; background: #f8fafc; padding: 40px 24px; color: #334155; }

    /* โ”€โ”€ Article with optimal readability โ”€โ”€ */
    .article {
      max-width: 65ch;        /* ~65 chars per line โ€” ideal measure */
      margin: 0 auto 48px;
      background: white;
      border-radius: 16px;
      padding: 40px 48px;
      border: 1px solid #e2e8f0;
    }

    .kicker {
      font-size: 0.7rem;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 0.1em;   /* wide tracking on uppercase */
      color: #4f46e5;
      margin-bottom: 12px;
    }

    .article h1 {
      font-family: 'Playfair Display', Georgia, serif;
      font-size: clamp(1.75rem, 4vw, 2.5rem);
      font-weight: 700;
      line-height: 1.15;        /* tight for large headings */
      letter-spacing: -0.025em; /* slightly tighter tracking */
      color: #0f172a;
      margin-bottom: 20px;
    }

    .byline {
      font-size: 0.85rem;
      color: #94a3b8;
      margin-bottom: 28px;
      padding-bottom: 28px;
      border-bottom: 1px solid #f1f5f9;
      letter-spacing: 0.01em;
    }

    .article p {
      font-size: 1rem;
      line-height: 1.75;        /* relaxed for body text */
      color: #475569;
      margin-bottom: 20px;
      /* First paragraph โ€” no indent */
    }

    /* Traditional book-style: indent after first paragraph */
    .article p + p {
      text-indent: 1.5em;
      margin-bottom: 16px;
    }

    .article h2 {
      font-size: 1.2rem;
      font-weight: 700;
      line-height: 1.3;
      letter-spacing: -0.01em;
      color: #0f172a;
      margin: 32px 0 12px;
    }

    /* โ”€โ”€ Spacing comparison โ”€โ”€ */
    .comparison {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 16px;
      max-width: 900px;
      margin: 0 auto;
    }
    .comp-box {
      background: white;
      border-radius: 12px;
      padding: 24px;
      border: 1px solid #e2e8f0;
    }
    .comp-label {
      font-size: 0.7rem;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 0.08em;
      color: #64748b;
      margin-bottom: 12px;
    }
    .tight  { line-height: 1.1; font-size: 0.9rem; color: #334155; }
    .loose  { line-height: 1.75; font-size: 0.9rem; color: #334155; }
  </style>
</head>
<body>

  <article class="article">
    <p class="kicker">CSS Typography</p>
    <h1>The Art of Readable Text on the Web</h1>
    <p class="byline">By Jane Smith · June 2025 · 5 min read</p>

    <p>Well-crafted typography is the foundation of every readable website. The spacing between lines, the width of the text column, and the subtle tightening of heading letter-spacing all work together invisibly to guide the reader's eye and reduce cognitive load.</p>

    <p>Research consistently shows that lines between 55 and 75 characters produce the fastest reading speeds and the highest comprehension. Wider columns force the eye to travel too far; narrower columns require too many line returns.</p>

    <h2>Line Height Is Not Just Aesthetic</h2>

    <p>A line-height below 1.4 on body text causes readers to re-read lines or lose their place. A line-height above 1.9 makes the reader feel the text is disconnected โ€” each line floats independently. The 1.6โ€“1.75 sweet spot creates rhythm without drift.</p>
  </article>

  <div class="comparison">
    <div class="comp-box">
      <p class="comp-label">line-height: 1.1 (too tight)</p>
      <p class="tight">This paragraph has a line-height of 1.1 โ€” far too tight for comfortable body reading. The lines crowd together and the eye struggles to track from the end of one line to the start of the next.</p>
    </div>
    <div class="comp-box">
      <p class="comp-label">line-height: 1.75 (ideal)</p>
      <p class="loose">This paragraph has a line-height of 1.75 โ€” comfortable and breathing. The eye can easily find the next line, and the text feels open without the lines feeling disconnected from each other.</p>
    </div>
  </div>

</body>
</html>

How It Works

Step 1 โ€” max-width: 65ch Enforces Optimal Measure

The ch unit equals the advance width of the “0” character. max-width: 65ch limits lines to approximately 65 characters โ€” within the typographically optimal 55โ€“75 range. Because it is relative to the font, the measure automatically adjusts when font-size or font-family changes.

Step 2 โ€” Unitless line-height Inherits Correctly

The body’s line-height: 1.75 is a ratio. A nested element with font-size: 0.75rem inherits the ratio 1.75 and applies it to its own 12px size, giving line-height of 21px. If we had set line-height: 28px, the nested element would also inherit 28px โ€” too loose for 12px text.

Step 3 โ€” Negative letter-spacing Tightens Large Headings

At large sizes (2rem+), the default browser letter-spacing between glyphs feels loose. letter-spacing: -0.025em pulls characters slightly closer, giving headings a more professional, publication-quality feel. The em unit means the tightening scales proportionally with font-size.

Step 4 โ€” Wide letter-spacing Improves Uppercase Labels

The kicker uses letter-spacing: 0.1em โ€” 10% of the font-size added between each character. All-caps text at small sizes becomes harder to read without tracking because capitals were designed with inter-character spacing in mind for mixed case. Adding tracking compensates.

Step 5 โ€” text-indent Creates Book Paragraph Style

Using the CSS sibling selector p + p (a paragraph directly after another paragraph), the text-indent: 1.5em applies only to subsequent paragraphs โ€” the traditional print convention where only the first paragraph of a section has no indent, while following paragraphs are indented.

Real-World Example: Editorial Article Stylesheet

/* editorial.css โ€” production article typography */
:root {
  --font-body:    'Georgia', serif;
  --font-ui:      'Inter', system-ui, sans-serif;
  --color-text:   #1c1917;
  --color-muted:  #78716c;
  --color-accent: #dc2626;
}

.prose {
  font-family:  var(--font-body);
  font-size:    clamp(1rem, 1.5vw, 1.125rem);
  line-height:  1.8;
  color:        var(--color-text);
  max-width:    68ch;
  margin-inline: auto;
}

/* Headings inside prose */
.prose h1 {
  font-family:    var(--font-ui);
  font-size:      clamp(2rem, 5vw, 3rem);
  font-weight:    800;
  line-height:    1.1;
  letter-spacing: -0.03em;
  margin-bottom:  0.75em;
  color:          var(--color-text);
}

.prose h2 {
  font-family:    var(--font-ui);
  font-size:      clamp(1.25rem, 2.5vw, 1.75rem);
  font-weight:    700;
  line-height:    1.25;
  letter-spacing: -0.02em;
  margin:         2em 0 0.75em;
  color:          var(--color-text);
}

.prose h3 {
  font-family:    var(--font-ui);
  font-size:      1.125rem;
  font-weight:    600;
  line-height:    1.4;
  letter-spacing: -0.01em;
  margin:         1.5em 0 0.5em;
}

/* Body paragraphs */
.prose p   { margin-bottom: 1.5em; }
.prose p + p { text-indent: 1.25em; }

/* Kicker / category label */
.prose .kicker {
  font-family:    var(--font-ui);
  font-size:      0.7rem;
  font-weight:    700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color:          var(--color-accent);
  display:        block;
  margin-bottom:  0.75em;
}

/* Blockquote / pull quote */
.prose blockquote {
  font-size:     1.2em;
  font-style:    italic;
  line-height:   1.5;
  border-left:   4px solid var(--color-accent);
  padding:       0.75em 1.25em;
  margin:        2em 0;
  color:         var(--color-muted);
}

/* Inline code */
.prose code {
  font-family: 'JetBrains Mono', 'Courier New', monospace;
  font-size:   0.875em;
  background:  #f5f5f4;
  padding:     0.15em 0.4em;
  border-radius: 4px;
  color:       #c2410c;
}

Common Mistakes

Mistake 1 โ€” Line height too tight for body text

โŒ Wrong โ€” default browser line-height of ~1.2 is too tight for long-form reading:

p { font-size: 1rem; } /* line-height: normal ~= 1.2 โ€” uncomfortable to read */

โœ… Correct โ€” set an explicit comfortable line-height on body text:

body { font-size: 1rem; line-height: 1.7; }

Mistake 2 โ€” No max-width on text content

โŒ Wrong โ€” long lines on wide screens are exhausting to read:

.article-body { padding: 40px; } /* text can stretch to full viewport width */

โœ… Correct โ€” constrain line length with ch units:

.article-body { max-width: 65ch; margin-inline: auto; padding: 40px 24px; }

Mistake 3 โ€” Adding letter-spacing to body text

โŒ Wrong โ€” positive letter-spacing on body text slows reading speed:

p { letter-spacing: 0.05em; } /* text looks "airy" โ€” readers decode each letter */

โœ… Correct โ€” leave body text at default tracking; only adjust for headings and labels:

h1     { letter-spacing: -0.02em; }  /* tighter for large headings */
.label { letter-spacing:  0.08em; }  /* wider for small uppercase labels */

▶ Try It Yourself

Quick Reference

Property Recommended Notes
line-height (body) 1.6โ€“1.75 (unitless) Never use px or em values โ€” they break inheritance
line-height (heading) 1.1โ€“1.3 Tighter for larger text
letter-spacing (heading) -0.01em to -0.04em Tighter tracking at large sizes
letter-spacing (uppercase) 0.05em to 0.1em Wider tracking improves all-caps readability
max-width (measure) 55ch to 75ch ch unit auto-adjusts to font changes
text-indent 1โ€“2em For print-style paragraph indentation

🧠 Test Yourself

Why should you use a unitless number for line-height rather than em or px?





โ–ถ Try It Yourself