text-wrap Performance with Large Text Blocks
Measured impact of text-wrap: balance and pretty on large pages and how to bound the cost in dynamic apps.
Detailed Explanation
The Cost Model
- text-wrap: nowrap / wrap: zero overhead. These are the legacy behaviors.
- text-wrap: pretty: roughly constant overhead per paragraph (look-ahead window of 4 lines). Negligible for any practical paragraph length.
- text-wrap: balance: O(n²) where n is the number of break candidates. Capped at 6 wrapped lines by all major browsers — past that, balance silently disables itself, so the cost is bounded.
Real numbers
Lighthouse audits and Chrome's tracing tool show that on a page with ~20 H1 and H2 elements all using text-wrap: balance, the layout pass adds well under 1ms. On a page with hundreds of paragraphs using text-wrap: pretty, the cost is essentially zero compared to font rendering.
The performance discussion only matters in two scenarios:
- Animation: text whose width animates every frame (60 layouts/sec).
- Hot edit loops: rich-text editors that re-flow on every keystroke.
Pattern 1: avoid balance on animated text
If a heading width is being animated (e.g. expand/collapse panel headers), prefer pretty or default wrap. Recomputing balance on every frame can cost 1-2ms per frame, which can push a 60fps experience down to 50fps on low-end devices.
Pattern 2: scope balance precisely
Don't apply balance globally:
/* Bad — balances everything */
* { text-wrap: balance; }
/* Good — scoped to elements that benefit */
h1, h2, h3, .card-title, .tooltip, .form-label {
text-wrap: balance;
}
Pattern 3: use stable in editors
text-wrap: stable (Chrome 121+) is designed for live-edited content. It produces consistent line breaks even as content changes, so the user's caret doesn't jump around. Use it on contenteditable elements:
[contenteditable] {
text-wrap: stable;
}
Measuring in your own app
Open Chrome DevTools → Performance, record a few seconds of interaction, and look at the "Layout" entries. If "text-wrap" appears in the bottom-up summary as a hot path, you have an actual problem worth investigating. In 99% of cases it won't.
When text-wrap: balance disables itself
You can verify the 6-line cap by setting a very narrow container that forces the text to wrap to 8 lines, then comparing balance vs default wrap. They will be identical. The browser silently switched off balance because the algorithm would have been too expensive.
Bottom line
For static pages, use balance and pretty liberally. For animation and live-edit loops, prefer pretty and stable. There's effectively never a case where you should fall back to JavaScript balancing for performance — the native CSS implementation is faster and simpler.
Use Case
High-performance SPAs, rich-text editors and CMSs (where text re-flows on every keystroke), landing pages with animated headlines, dashboards with thousands of text widgets, server-side rendered sites measuring TTFB and LCP.