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:
| Context | How measure is expressed |
|---|---|
| Print / traditional | Picas, ciceros, or character counts |
| Web CSS | ch, em, rem, px, or % |
| Design tools (Figma) | Fixed pixel width on a text frame |
| Design tokens | A 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
60chis literally 60 characters wide. This is wherechis 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,
1chapproximates the average character width well enough that60chtracks 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
60chmay visually jump when the web font swaps in, if the fallback and display fonts have substantially different character widths. Pairch-based measure with careful font loading — see the Web Fonts lesson — andfont-display: optionalorsize-adjustdescriptors to minimize reflow.
ch vs other units for measure
| Unit | Relative to | Good for measure? |
|---|---|---|
px | Screen pixels | No — breaks zoom accessibility |
% | Parent container width | Fragile — depends on layout context |
em | Current font size | Usable but not character-width-calibrated |
rem | Root font size | Same as em; better for scaling, not measure |
ch | Zero-glyph advance width | Yes — directly character-width-calibrated |
vw | Viewport width | Dangerous 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: 65chon your.proseor 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-widthinpx— 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
chis 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.