UI/UX Atlas
Typography Intermediate

Line Length (Measure) & the ch unit

Controlling how wide a line of text runs is one of the highest-leverage readability decisions a designer can make — and CSS now gives us a precise, glyph-aware unit to do it.

9 min read

The full lesson

Typographers have known for centuries that reading comfort depends on how far the eye must travel across a line before snapping back to the start of the next one. Too short, and the eye trips over constant line breaks. Too long, and it loses its place on the return trip.

Modern CSS introduced the ch unit to bring that classical wisdom into responsive layouts. Yet it remains one of the most misunderstood CSS units in daily practice.

This lesson covers the theory behind optimal line length, how the ch unit works and what it actually measures, practical patterns for constraining measure in real interfaces, and the common mistakes that hurt readability.

What “Measure” Means in Typography

In traditional typography, measure is the width of a text column — the horizontal distance a single line of body copy spans. The term comes from hand-setting metal type, where a compositor literally measured a composing stick to set column width.

Today, measure is expressed differently depending on context:

ContextHow measure is expressed
Print / traditionalPicas, ciceros, or character counts
Web CSSch, em, rem, px, or %
Design tools (Figma)Fixed pixel width on a text frame
Design tokensA max-width or width token on a prose container

The key insight: measure is a container property, not a font-size property. You control measure by constraining the width of the element that wraps your text — not by changing the type size.

The Optimal Range and Its Research Basis

The widely cited optimal range for body text is 45–75 characters per line, with 66 characters often named as the ideal. Robert Bringhurst codified this in The Elements of Typographic Style. Eye-tracking and reading-speed studies broadly support it — though the research is more nuanced than a single number suggests.

Here is what the evidence shows at the extremes:

  • Very short lines (under 35 ch) force frequent line returns. The eye makes more saccades (rapid movements), and comprehension drops because the brain must continuously re-anchor context.
  • Long lines (over 90 ch) cause “line re-entry errors” — the eye, returning from the right margin, lands on the wrong line. This shows up as more regressive saccades and lower comprehension.
  • The 45–75 ch range balances saccade economy with comfortable return trips. Within this range, individual preference and typeface geometry both shift the sweet spot.

For UI microcopy — labels, captions, tooltips, helper text — shorter lines (25–40 ch) are fine and often preferable. That text is scanned rather than read linearly. The 45–75 rule is a body-copy guideline.

How the ch Unit Works

The CSS ch unit equals the advance width of the “0” (zero) glyph in the current font at the current size. “Advance width” is the full horizontal space a character occupies — glyph width plus side bearings — which determines how far the cursor moves after drawing that character.

This makes ch a font-relative unit, like em, but tied to a specific glyph rather than to cap-height or x-height.

What ch measures and what it does not

Because ch is anchored to the zero glyph specifically, its precision depends on the font:

  • In monospaced fonts, every character has the same advance width. So 60ch is literally 60 characters wide. This is where ch is most accurate.
  • In proportional fonts (nearly every body typeface), character widths vary. The zero glyph is typically a bit narrower than an uppercase letter and a bit wider than a lowercase letter. In practice, 1ch approximates the average character width well enough that 60ch tracks close to 60 average characters — but it is an approximation.
  • If no font has loaded yet (during a flash of unstyled text, or before a web font applies), the browser uses the fallback font’s zero-glyph width. A container set to 60ch may visually jump when the web font swaps in, if the fallback and display fonts have substantially different character widths. Pair ch-based measure with careful font loading — see the Web Fonts lesson — and font-display: optional or size-adjust descriptors to minimize reflow.

ch vs other units for measure

UnitRelative toGood for measure?
pxScreen pixelsNo — breaks zoom accessibility
%Parent container widthFragile — depends on layout context
emCurrent font sizeUsable but not character-width-calibrated
remRoot font sizeSame as em; better for scaling, not measure
chZero-glyph advance widthYes — directly character-width-calibrated
vwViewport widthDangerous alone — use only inside clamp()

Applying Measure in CSS

The standard pattern for constraining body text measure:

.prose {
  max-width: 65ch;
}

This tells the browser: never let this container exceed the width of 65 zero glyphs in the active font. The column automatically narrows if font size increases — from browser zoom, user preferences, or responsive fluid sizing — keeping line lengths comfortable.

Combining ch with clamp() for fluid measure

On very small viewports, a 65ch max-width may still be wider than the screen, causing overflow. On very wide viewports, you may want slightly wider columns in multi-column layouts. The clamp() pattern handles both edges:

.prose {
  width: clamp(30ch, 65ch, 80ch);
}

The column is always at least 30ch, ideally 65ch, and never more than 80ch. Because all three values are in ch, they all scale with font size and typeface — the measure relationship holds in any context.

For fully fluid, viewport-responsive layouts, you can blend ch and vw inside clamp():

.prose {
  width: clamp(30ch, 50vw + 10ch, 75ch);
}

The middle expression (50vw + 10ch) acts as the ideal: it grows with viewport width but has a floor in character units, so it never collapses past a readable width on narrow screens.

Where to apply the constraint

A common mistake is applying max-width: 65ch to the wrong element — often the entire page wrapper or a card container that also holds images, buttons, and other UI. The constraint should target the text’s direct parent or a dedicated .prose wrapper around body copy:

/* Correct: narrow only the text column */
article .body-text {
  max-width: 65ch;
}

/* Too broad: also narrows images, pullquotes, code blocks */
article {
  max-width: 65ch;
}

In component-based systems (React, Vue, Astro), a <Prose> wrapper component is a clean solution. It applies the measure constraint in one place and can be themed via a CSS custom property:

.prose {
  --prose-measure: 65ch;
  max-width: var(--prose-measure);
}

This surfaces the measure as a design token — auditable and overridable per context without touching component logic.

Measure in Responsive Layouts

Fluid typography (covered in the Responsive and Fluid Typography lesson) changes font size continuously with viewport width. When you scale font size with clamp(), a ch-based measure constraint adjusts automatically. The column stays calibrated to the number of characters per line even as type size grows or shrinks. This is the core advantage of ch over px for measure.

On narrow viewports (mobile), max-width: 65ch typically fills nearly the full screen width — which is appropriate. You rarely need a separate breakpoint override for prose measure.

On wide viewports, the challenge is preventing text from expanding to fill a 1400px-wide container. Here max-width: 65ch does all the work — the column stays narrow even when the layout grid has spare space. The old approach of setting a fixed max-width: 680px on an article body fails at larger font sizes and is now considered outdated.

Multi-Column Text and Narrow Measure

CSS multi-column layout (column-count, column-width) can create a measure problem: each column may be only 20–30ch wide. That is comfortable for newspaper scanning but uncomfortable for deep reading. If you use multi-column for long-form prose, check each column’s effective measure at your breakpoints.

The column-width property accepts ch. Setting column-width: 40ch tells the browser to create as many columns as fit while keeping each at least 40ch wide — a content-driven approach that avoids locking in a column count:

.newspaper {
  column-width: 40ch;
  column-gap: 2rem;
}

This is one of the few cases where a wider-than-66ch total container width makes sense: the multiple narrow columns each stay within the optimal range.

Design Tokens and Measure

In a design token system, measure belongs in the semantic layer. It is not a raw primitive like a color value — it is a purposeful decision tied to reading context. A well-structured token set might look like:

{
  "prose-measure": { "$value": "65ch", "$type": "dimension" },
  "prose-measure-narrow": { "$value": "50ch", "$type": "dimension" },
  "prose-measure-wide": { "$value": "80ch", "$type": "dimension" }
}

The W3C DTCG stable format ($value and $type) makes these tokens platform-portable. They can be consumed by CSS custom properties, Figma variables, and native platforms alike. Hardcoding 65ch directly in component stylesheets is fine in small projects. In larger systems with multiple reading contexts — marketing site, documentation, in-app help — it becomes a maintenance burden.

Common Mistakes and How to Avoid Them

Do

  • Set max-width: 65ch on your .prose or article body wrapper.
  • Use clamp(30ch, 65ch, 80ch) to add floor and ceiling behavior.
  • Test measure at 200% browser zoom to verify it still reads comfortably.
  • Apply distinct measure values for body copy (45–75ch) vs. UI microcopy (25–40ch).
  • Expose measure as a CSS custom property or design token for system-level consistency.

Don't

  • Don’t use a fixed max-width in px — it breaks when the user zooms or changes their font size.
  • Don’t apply measure constraints to the outer layout wrapper — it will clip images, code blocks, and UI chrome that should run full-width.
  • Don’t assume ch is exactly one character — in proportional fonts it is an approximation; audit visually at your target font.
  • Don’t skip measure constraints on wide-viewport layouts and rely on the grid to keep columns narrow — a stray width: 100% will create dangerously long lines.
  • Don’t set the same measure for headings and body text — headings are scanned, not read linearly, and can tolerate wider spans.

Outdated pattern: pixel-locked article widths

A widespread legacy pattern sets a fixed pixel max-width on article content:

/* outdated */
article {
  max-width: 680px;
  margin: 0 auto;
}

At a 16px browser default with a typical proportional font, 680px yields roughly 65–70 characters per line — coincidentally good. But at 20px (a common default for users with vision differences), 680px holds only 52–54 characters. At 24px, it drops to 44 — at the edge of the too-short range.

The ch-based equivalent (max-width: 65ch) auto-corrects. The column width scales with the font, so the character count per line stays in the comfortable range at any font size.

Accessibility Implications

WCAG 2.2 Success Criterion 1.4.8 (Level AAA) addresses visual presentation of text. It explicitly requires that “width is no more than 80 characters or glyphs.” AAA is not the legal baseline for most products (AA is), but this criterion exists because the evidence for measure’s impact on readability is strong enough that the W3C encoded it into the standard.

More practically, the 1.4.4 Resize Text criterion (Level AA) requires that text can be resized up to 200% without loss of content or functionality. A ch-based measure constraint automatically satisfies the spirit of this requirement. As the user zooms, the column narrows in character-count terms to compensate, preventing extreme line lengths at any zoom level. A px-locked column does not adapt and may violate the criterion if content overflows.

Screen reader users are largely unaffected by visual measure. But users with cognitive disabilities — including dyslexia, ADHD, and low literacy — measurably benefit from shorter line lengths and ample line height. Measure is a concrete lever for cognitive accessibility, not just an aesthetic choice.