CSS · typography · web standards
CSS text-wrap: balance
You have written a three-line heading and the third line contains one word. It looks like a mistake, it is not one, and until recently the only fixes were a manual line break or a non-breaking space that stopped being correct the moment the viewport changed.
The declaration is one line:
h1, h2, h3 {
text-wrap: balance;
} The browser then distributes the words so that the lines come out close to equal length, instead of filling each line greedily and leaving whatever remains on the last one.
Why it is restricted to short text, and this is in the specification
Normal line breaking is greedy: fill a line, move on, never look back. Balancing is not, because the browser has to try several distributions and compare them. That work grows with the number of lines, which is why the specification allows implementations to cap it.
Chromium applies the property to blocks of six lines or fewer and ignores it beyond that. The limit is not a bug and not something to work around: it is what keeps a paragraph of forty lines from costing a layout pass it does not deserve. Applying balance to p is therefore not dangerous, it is simply ignored on anything long, which makes it a declaration that does nothing while looking like it does something.
balance, pretty, and stable are three different jobs
text-wrap: pretty is the one for body copy. It does not equalise line lengths; it avoids typographic orphans, the single word left on the final line of a paragraph, and it does so with a much smaller performance cost because it only reconsiders the end of the block.
text-wrap: stable matters for text that changes as the user types. Without it, editing the middle of a paragraph can reflow every following line and make the text appear to jump. With it, lines before the cursor stay where they are.
The short version: balance for headings, pretty for paragraphs, stable for editable regions. They are not stronger and weaker versions of one another.
What happens in a browser that does not support it
Nothing, which is the correct behaviour. An unknown value for text-wrap is dropped at parse time and the element wraps the way it always did. That makes this a genuine progressive enhancement: no feature query required, no fallback to write, no layout difference beyond a heading that breaks less elegantly.
If you want to branch on it anyway, @supports (text-wrap: balance) works, but for this property it is usually ceremony around a no-op.
Where it goes wrong in practice
Applied to every element. A universal selector with balance is silently ignored on long blocks and costs layout work on the short ones. Target headings, captions, and blockquotes, which is where the visual problem actually appears.
Combined with a fixed width. Balancing chooses break points; it does not change how much room the text has. A heading in a narrow column with long words will still break awkwardly, and the property has nothing to offer there.
Expected to fix a widow in body text. That is the job of pretty. Reaching for balance and concluding the feature is broken is the most common way people meet the six line cap without realising it.
The one line worth adopting
For most sites this is a three line change in a stylesheet, applied to headings only:
h1, h2, h3, h4, figcaption, blockquote {
text-wrap: balance;
}
p, li {
text-wrap: pretty;
} It degrades to nothing where unsupported, it needs no JavaScript, and it removes a category of manual line breaks from your templates. Related reading: CSS container queries.