text-wrap: balance and pretty: Better Line Breaks Without Manual Breaks
Responsive layouts reflow text constantly, and the browser's default line breaking is greedy: it fills each line as much as possible and moves on. That produces two familiar blemishes. A two-line heading has a full first line and a second line holding one or two words, so the heading looks lopsided. A paragraph ends with a single orphaned word on its last line, wasting a line of vertical space and drawing the eye. Designers used to fix both with manual <br> tags or non-breaking spaces, which break as soon as the width changes. The text-wrap property now lets the browser choose better breaks at every width. This page explains what balance and pretty do, their limits, their cost, and where they help or hurt. It belongs to Fluid Typography With clamp() in the Mastering Container Queries & Responsive Layouts guide.
Why manual fixes fail in fluid layouts
A <br> inserted to balance a heading is correct at exactly one width. With fluid type and container-driven layouts, the heading's size and its container's width both change continuously, so a hand-placed break is wrong almost everywhere — often producing a three-line heading with a stub in the middle. Non-breaking spaces between the last two words prevent single-word last lines but can overflow narrow containers. Both techniques encode a layout assumption in content, which is the opposite of how responsive design should work.
text-wrap moves the decision into the layout engine, where the real width is known on every reflow.
What each value does
text-wrap: wrap(default) — greedy wrapping.text-wrap: nowrap— no wrapping, equivalent to the oldwhite-space: nowrapfor this purpose.text-wrap: balance— chooses breaks so all lines are close to equal length. The browser effectively searches for the narrowest width at which the text still fits in the same number of lines. Limited to short blocks; browsers cap the number of lines they will balance, and beyond that cap the text wraps normally.text-wrap: pretty— uses greedy wrapping for most of the block but considers the last several lines together, adjusting breaks to avoid a very short final line and other typographic blemishes. Designed for body text.text-wrap: stable— keeps earlier lines from rewrapping while text is edited, useful in editable fields.
text-wrap is a shorthand for text-wrap-mode (wrap or nowrap) and text-wrap-style (auto, balance, pretty, stable). In practice the shorthand is what gets written.
The complete implementation
The article below applies balance to headings, captions and pull quotes, and pretty to paragraphs and list items. Resize the demo to watch the heading keep its lines even at every width.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>text-wrap balance and pretty</title>
<style>
body { font: 17px/1.6 Georgia, serif; margin: 1.5rem; }
.prose { max-width: 60ch; }
/* Short, prominent text: balance every line. */
.prose :is(h1, h2, h3, figcaption, blockquote p) {
text-wrap: balance;
}
/* Headings with a background should hug their balanced text,
otherwise the box stays full width with empty space at line ends. */
.prose .tag-heading {
width: fit-content;
padding: 0.2em 0.5em;
background: #eef2ff;
}
/* Running text: keep normal wrapping, but fix the ending. */
.prose :is(p, li) {
text-wrap: pretty;
}
/* Code and preformatted text must never be rewrapped. */
.prose :is(pre, code) {
text-wrap: nowrap;
}
h1 { font-size: clamp(1.8rem, 1.2rem + 3vw, 3rem); line-height: 1.1; }
</style>
</head>
<body>
<article class="prose">
<h1>A field guide to the tidal flats of the northern estuary</h1>
<p>The flats are exposed twice a day, and in that window they become one of the richest
feeding grounds on the coast for waders, gulls and the occasional patient heron.</p>
<h2 class="tag-heading">Reading the tide tables before you go</h2>
<p>Always check the tables before walking out; the water returns faster than it seems.</p>
</article>
</body>
</html>
The .tag-heading rule shows the one interaction people miss: balancing shortens the lines but not the element. A heading with a background colour would otherwise show a full-width box with empty space at the end of each short line. width: fit-content shrinks the box to its longest line, which after balancing is the natural width of the text.
The key technique: balance for short text, pretty for long
The two values solve different problems, and swapping them does not work well.
Balancing a paragraph would, if browsers allowed it, shorten every line to match the shortest arrangement — wasting horizontal space and making body text less efficient to read. That is why browsers cap it to a few lines. Applying pretty to a two-line heading, conversely, changes little, because a heading's problem is its first line being too long relative to the second, not a stray last word.
Interactions with fluid type and animation
Both values are recomputed whenever the text reflows, so they cooperate naturally with fluid typography and container-driven layout: every size and width gets balanced lines. Two interactions deserve care.
First, animating font size or container width on text with balance rebalances on every frame, which is both expensive and visually busy — lines jump between arrangements as the animation runs. Animate a transform: scale() instead when a heading must grow, so the text reflows once, or disable balancing during the animation.
Second, balanced text is narrower than its box, which affects anything aligned to the text's edge. Underlines drawn with borders on the heading element span the full box width; underlines drawn with text-decoration follow the text. For headings with decorative lines, prefer text-decoration or apply width: fit-content. The motion side of heading reveals — clipping a balanced heading into view — is covered in Clip-Path Reveal Animations.
Rolling it out across a site
Because both values only improve line breaks and never change content, they can be introduced site-wide with low risk, but a few checks make the rollout smooth.
Apply by element role, not by class. A base rule such as h1, h2, h3, figcaption { text-wrap: balance; } and p, li, dd { text-wrap: pretty; } covers most content without touching component markup. Component styles can then opt out where needed.
Audit headings with trailing icons or badges. A heading containing an inline "New" badge or an external-link icon is balanced together with that content, which occasionally moves the badge onto its own line. Wrapping the last word and the badge in a white-space: nowrap span keeps them together.
Check narrow containers. Balance never produces more lines than greedy wrapping would; it only redistributes them. But in very narrow containers, such as table headers or sidebar cards, balanced headings can look oddly narrow. Opting those contexts out with text-wrap: wrap is a legitimate choice.
Compare screenshots before and after. Visual regression tests will show many small line-break changes on the first run. Review a sample to confirm they are improvements, then approve them in bulk; subsequent runs will be stable.
Mind translated content. Languages with long compound words or no spaces between words wrap differently, and balancing can behave unexpectedly with very long unbreakable words. Test headings in the site's longest-word language, and make sure overflow-wrap: anywhere or hyphenation is available where words may exceed the column.
Accessibility notes
Neither value changes the text itself; screen readers read it exactly as before, and copy-and-paste yields the same characters. Better breaks are an accessibility improvement for readers with dyslexia or low vision, who benefit from lines of more even length and fewer isolated words. Unlike manual <br> tags, text-wrap never injects line breaks that screen readers might announce as pauses, and it adapts correctly when users zoom or increase text spacing under WCAG 1.4.12.
Browser support
text-wrap: balance is supported in Chrome and Edge 114+, Firefox 121+ and Safari 17.5+. text-wrap: pretty is supported in current Chromium browsers and Safari; in engines without it, the value is ignored and text wraps normally, so it is safe to apply unconditionally. fit-content sizing is supported in Chrome and Edge 46+ and 79+, Firefox 94+ and Safari 11+.
FAQ
What is the difference between text-wrap: balance and pretty?balance tries to make all lines of a block roughly equal in length, which suits short headings and captions. pretty keeps normal greedy wrapping for most of the text but adjusts the last few lines to avoid a very short final line, which suits body paragraphs.
Why does text-wrap: balance not work on my paragraph?
Browsers limit balancing to short blocks, a handful of lines, because the algorithm is expensive and balancing long paragraphs makes little visual difference. Beyond the limit the text wraps normally. Use pretty for paragraphs instead.
Does text-wrap: balance change the width of the element?
No. The element keeps its width; the text inside is wrapped with shorter lines so they are more even, which leaves space at the end of each line. If the heading's background or border should shrink to the text, combine balance with width: fit-content.
Is text-wrap: pretty expensive?
It does more work than normal wrapping, but browsers limit it to the end of paragraphs. On typical article pages the cost is negligible. Avoid applying it to very large amounts of frequently changing text, such as live-updating logs.
Related
- Fluid Typography With clamp() — the parent guide.
- Fluid Line Height and Measure — the other half of readable line layout.
- min-content, max-content and fit-content — shrinking boxes to balanced text.
- Optimizing CSS Animations for 60fps — why reflowing text should not be animated.
Related articles
More pages in the same section.