Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified public/og-default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/og/checklist.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/og/spec.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/og/spec/foundations.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/og/spec/foundations/text-wrap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions src/content/changelog/2026-06-25-text-wrap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
title: New page on balanced text wrapping
date: "2026-06-25"
type: added
relatedSlugs: [text-wrap]
---

Added a page on [balanced text wrapping](/spec/foundations/text-wrap/) — using `text-wrap: balance` on headings and `text-wrap: pretty` on body copy (CSS Text Module Level 4) so the browser breaks lines intelligently instead of stranding a lone word, with no manual `<br>` hacks and a clean fallback where unsupported. This site now ships both in its own stylesheet.
2 changes: 1 addition & 1 deletion src/content/spec/foundations/color-scheme.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ summary: "Tells the browser which colour schemes your page is designed for. Prev
status: recommended
order: 95
appliesTo: [all]
relatedSlugs: [theme-color, favicons, pwa-manifest, forced-colors]
relatedSlugs: [theme-color, favicons, pwa-manifest, forced-colors, text-wrap]
updated: "2026-05-29T17:40:31.000Z"
sources:
- title: "HTML Living Standard — Standard metadata names: color-scheme"
Expand Down
72 changes: 72 additions & 0 deletions src/content/spec/foundations/text-wrap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
title: "Balanced text wrapping"
slug: text-wrap
category: foundations
summary: "Let the browser break headings and body copy intelligently with text-wrap: balance and pretty — no orphaned words, no manual line breaks, no layout shift."
status: recommended
order: 150
appliesTo: [all]
relatedSlugs: [color-scheme, font-loading, core-web-vitals]
updated: "2026-06-25T00:00:00.000Z"
sources:
- title: "CSS Text Module Level 4 — the text-wrap shorthand"
url: "https://drafts.csswg.org/css-text-4/#text-wrap"
publisher: "W3C CSS Working Group"
- title: "MDN — text-wrap"
url: "https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/text-wrap"
publisher: "MDN"
- title: "CSS text-wrap: balance"
url: "https://developer.chrome.com/docs/css-ui/css-text-wrap-balance"
publisher: "Chrome for Developers"
- title: "Better typography with text-wrap: pretty"
url: "https://webkit.org/blog/16547/better-typography-with-text-wrap-pretty/"
publisher: "WebKit"
---

## What it is

`text-wrap` is a CSS shorthand that tells the browser _how_ to break a run of text across lines, beyond the default greedy "fill each line, then break". Two values matter for content:

- **`text-wrap: balance`** — even out the number of characters per line so a block doesn't end on a lonely word. Best for short runs: headings, blockquotes, captions, card titles. Browsers cap it (six lines in Chromium, ten in Firefox), so it stays cheap.
- **`text-wrap: pretty`** — optimise the _last few_ lines of a longer block to avoid orphans (a single word on the final line) and bad breaks. Intended for body copy.

Both are part of the `text-wrap` shorthand in CSS Text Module Level 4, alongside `text-wrap-mode` (`wrap` / `nowrap`) and `text-wrap-style` (which carries `balance` / `pretty` / `stable`).

```css
h1,
h2,
h3 {
text-wrap: balance;
}
p {
text-wrap: pretty;
}
```

## Why it matters

- **Readability.** A heading that wraps "Balanced text\nwrapping" reads better than one that leaves "wrapping" stranded alone. Avoiding orphans and ragged breaks is a typographic baseline print has always had.
- **No manual line breaks.** The common workaround — `<br>` or `&nbsp;` to force "good" wrapping — breaks the moment the viewport, font, or translated string changes. `balance` adapts to whatever width it is given.
- **It degrades safely.** Unsupported browsers ignore the declaration and fall back to normal wrapping. There is no polyfill, no JavaScript, and no layout to repair. `balance` is also cheap — browsers cap it to a handful of lines — though `pretty` is not (see below).

This site ships it: `text-wrap: balance` on spec headings and `text-wrap: pretty` on body paragraphs, in [`global.css`](https://github.com/jdevalk/specification.website/blob/main/src/styles/global.css).

## How to implement

Apply `balance` to short, heading-like elements and `pretty` to flowing prose. Set it globally in your base stylesheet; you do not need a feature query because the fallback is simply default wrapping.

Reserve `balance` for short blocks — the browser stops balancing past its line cap, so using it on long paragraphs does nothing useful. Use `pretty` for the long stuff.

Unlike `balance`, `pretty` is not free: it deliberately trades layout speed for typography, running a slower algorithm with no line cap, so the cost scales with how much text it touches. That is a fine trade for genuine body copy, but think before blanket-applying it to every text node on the page — scope it to your prose containers rather than a bare `*` or `p` selector across the whole document.

## Common mistakes

- **`balance` on long body text.** Past the browser's line cap it is a no-op, and where it does apply to long blocks it can cost layout performance. Keep it for headings and other short runs.
- **Keeping old `<br>` hacks.** Manual breaks fight the browser's balancing and produce double breaks at some widths. Remove them once you adopt `text-wrap`.
- **Expecting `pretty` everywhere.** Engine support for `pretty` trails `balance`; treat it as a progressive enhancement, never as something a layout depends on.
- **Applying `pretty` indiscriminately.** It runs a slower wrapping algorithm by design, and unlike `balance` it has no line cap, so applying it site-wide carries a real layout cost. Reserve it for actual body copy; do not hang it off a universal selector.

## Verification

- In a supporting browser, resize a balanced heading: the lines stay evenly filled rather than leaving a one-word last line.
- `caniuse.com/css-text-wrap-balance` — `balance` is Baseline across Chromium, Firefox, and Safari; `pretty` has narrower support.
2 changes: 1 addition & 1 deletion src/content/spec/performance/font-loading.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ summary: "Self-host WOFF2 fonts, subset them, set font-display: swap so text is
status: recommended
order: 70
appliesTo: [all]
relatedSlugs: [preload-prefetch-preconnect, critical-css, core-web-vitals]
relatedSlugs: [preload-prefetch-preconnect, critical-css, core-web-vitals, text-wrap]
updated: "2026-05-29T20:27:54.000Z"
sources:
- title: "MDN — @font-face"
Expand Down
8 changes: 8 additions & 0 deletions src/styles/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ body {
margin-bottom: 0.75rem;
letter-spacing: -0.01em;
scroll-margin-top: 7rem;
/* Even out short heading wraps so they don't strand a lone word.
Falls back to normal wrapping where unsupported. See
/spec/foundations/text-wrap/. */
text-wrap: balance;
}
.prose-spec > :first-child,
.prose-spec h2:first-child,
Expand All @@ -126,6 +130,7 @@ body {
margin-top: 1.75rem;
margin-bottom: 0.5rem;
scroll-margin-top: 7rem;
text-wrap: balance;
}
.prose-spec h4 {
font-size: 1rem;
Expand All @@ -136,6 +141,9 @@ body {
}
.prose-spec p {
margin-bottom: 1rem;
/* Avoid orphans on the last line of body copy where supported;
ignored otherwise. See /spec/foundations/text-wrap/. */
text-wrap: pretty;
}
.prose-spec ul,
.prose-spec ol {
Expand Down
Loading