text-box-trim is usable now: cut the dead space around headings

Line boxes are always taller than the glyphs, so that half-leading above a heading used to be fixed with negative margins. text-box-trim does it properly.

There is one place in typography where everyone has quietly been settling for less: line boxes are taller than the letters.

A font’s ascent and descent are metrics meant for line breaking, not visual boundaries. So a heading with line-height: 1.2 always carries roughly half of “line height minus glyph height” above it. Inside a card, that shows up as “there is no padding here, yet the heading will not sit flush.”

What we did before

Two workarounds, neither good:

  • Hand-tuned negative margins. margin-top: -0.6em and friends. Change the font or the size and it breaks.
  • Em-based estimates. The same guess, written more politely.

Both bake a font metric into the stylesheet. Swap the typeface and you start over.

What it looks like now

h1, h2, h3 {
  text-box-trim: trim-both;
  text-box-edge: cap alphabetic;
}

trim-both trims the first and last line box. text-box-edge says where to cut: cap alphabetic means “top edge to the cap height, bottom edge to the baseline”. Those two values cover almost every heading case.

It trims according to font metrics, so different typefaces lose different amounts. That is exactly what I want: I am after optical alignment, not numeric alignment.

Three things to watch

It only affects the first and last line. Line spacing in between is still line-height’s job. They do not conflict — just do not expect text-box-trim to set your leading.

Block-level boxes only. Inline elements have no independent line box edge, so the property does nothing there. To trim a <span>, make it display: block or inline-block first.

CJK font metrics are looser. Latin fonts have a well-defined cap height; CJK fonts often set ascent generously, so the trimmed result can look tighter than you expected. Try it on one heading before rolling it out site-wide.

What I settled on

Headings and buttons only. Not body copy.

If the first line of a paragraph sits flush against the top of its container, it reads as cramped — body text wants that breathing room. A heading or a button is a solid block of colour, and the space above it is noise, not rhythm.

This is the same position I take on text-wrap: balance: typographic properties should fix what the eye sees, not what the numbers table says. And text-box-trim is one of the few properties that genuinely does the former.

← Back to all posts

Comments

…