Skip to main content
  • Created:
  • Updated:
  • Author:
    Takeshi Takatsudo

Line Height Best Practices

The Problem

Line height is one of the most misunderstood CSS properties. AI agents frequently use values with units (line-height: 24px or line-height: 1.5em), which causes inheritance problems when child elements have different font sizes. The result is text that is either too cramped or too spaced, especially in components where font sizes vary between headings, body text, and small text.

The Solution

Use unitless line-height values. A unitless value is inherited as a ratio, meaning each element recalculates its actual line height based on its own font size. This prevents the common bug where a parent's computed line-height in pixels is inherited by children with different font sizes.

How Unitless vs Unit-Based Inheritance Works

/* PROBLEMATIC: unit-based line-height */
.parent {
font-size: 16px;
line-height: 24px; /* computed: 24px */
}

.parent h2 {
font-size: 32px;
/* Inherits line-height: 24px — text overlaps! */
}

/* CORRECT: unitless line-height */
.parent {
font-size: 16px;
line-height: 1.5; /* computed: 24px (16 × 1.5) */
}

.parent h2 {
font-size: 32px;
/* Inherits line-height ratio 1.5 → computed: 48px (32 × 1.5) */
}

Code Examples

:root {
/* Base line-height for body text */
line-height: 1.5;
}

/* Body text: 1.5 to 1.6 for optimal readability */
p,
li,
dd,
blockquote {
line-height: 1.5;
}

/* Headings: tighter line-height since large text needs less leading */
h1 {
line-height: 1.1;
}

h2 {
line-height: 1.2;
}

h3 {
line-height: 1.3;
}

h4,
h5,
h6 {
line-height: 1.4;
}

/* Small text / captions: slightly more line-height for readability */
small,
.caption,
.footnote {
line-height: 1.6;
}

/* Code blocks: tighter to keep code compact */
pre,
code {
line-height: 1.4;
}
Line Height Comparison — Tight (1.2) vs Normal (1.5) vs Loose (2.0)

Line Height with Fluid Typography

:root {
--line-height-tight: 1.1;
--line-height-snug: 1.3;
--line-height-normal: 1.5;
--line-height-relaxed: 1.6;
--line-height-loose: 1.8;
}

h1 {
font-size: clamp(2rem, 1.5rem + 2.5vw, 3.5rem);
line-height: var(--line-height-tight);
}

p {
font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
line-height: var(--line-height-normal);
}

Using the lh Unit for Spacing

The lh unit represents the computed line-height of the element, enabling spacing that aligns with the text rhythm.

p {
line-height: 1.5;
margin-block-end: 1lh; /* Margin equals one line of text */
}

blockquote {
line-height: 1.5;
padding-block: 0.5lh; /* Half a line of padding */
border-inline-start: 0.125lh solid currentColor;
}

Common AI Mistakes

  • Using line-height: 24px or line-height: 1.5em instead of the unitless 1.5, causing inheritance bugs
  • Applying the same line-height to headings and body text — headings need tighter values (1.1 to 1.3)
  • Setting line-height: 1 (or the normal keyword) for body text, which is too tight for readability. The normal keyword typically resolves to around 1.2 depending on the font, which is below the WCAG recommendation
  • Using line-height: 2 or higher for body text, which creates excessive spacing and makes paragraphs look disconnected
  • Forgetting that line-height affects the clickable area of inline elements and links
  • Not accounting for the font's built-in metrics — some fonts (especially decorative ones) need different line-height values than standard sans-serif fonts

When to Use

Every text element should have an intentional line-height value. The general guidelines are:

  • Body text (paragraphs, lists): 1.5 to 1.6 — this meets WCAG 1.4.12 (Text Spacing) requirements
  • Headings: 1.1 to 1.3 — large text reads well with tighter leading
  • Display / hero text: 1.0 to 1.15 — very large text can be even tighter
  • Small text / captions: 1.5 to 1.7 — small text benefits from extra breathing room
  • UI elements (buttons, badges): 1 to 1.2 — where vertical centering matters more than reading flow

References