The Figma spec says 24px between the nav and the headline. You build it, open devtools, and there's clearly more than 24px of air sitting above the letters. You didn't misread the spec. The browser is reserving space your design tool never shows you.
So you do what everyone does: nudge the heading up with a negative margin until the ruler in devtools finally reads 24px. It works — for this font, at this size, in this browser. Change the font, bump the line-height for mobile, or open it in Safari, and the gap is back, just a slightly different size than before.
You've been fighting your font's ascent metrics and your line-height's half-leading. CSS just shipped a property that ends the fight without a single magic number.
The hack, and why it's cursed
Here's the fix most people reach for first:
.headline {
font-size: 4rem;
line-height: 1.1;
margin-top: -0.18em; /* "close enough" nudge */
}
That -0.18em came from eyeballing devtools until the gap looked right. It's not derived from anything — it's a guess tuned to one font, one weight, one line-height. Swap the font from Inter to Georgia and the ratio of reserved space to cap-height changes, because different typefaces ship wildly different internal metrics. Your carefully tuned -0.18em now either under- or overshoots, and you're back in devtools with a ruler.
This got common enough that an entire library exists just to compute the right number for you: Capsize, built at SEEK, reads a font's actual metrics (ascent, descent, cap height, unitsPerEm — the numbers baked into the font file) and generates the precise negative margins to trim it. It's clever, it works, and it's also a small build step and a metrics lookup table for a problem that shouldn't need either.
What's actually eating the space
line-height doesn't measure your capital letters and add padding around them. It works from the font's own ascent and descent metrics — numbers baked in by whoever designed the typeface, sized to leave room for the tallest accented character the font ever needs to render, like Å or ĝ. Every line box gets that full reserved height whether or not a single accented character appears anywhere on your page — and line-height then adds half its extra spacing (the "half-leading") above it and half below.
Crank line-height up for readability — which you should, body copy wants 1.5 to 1.6 — and you're not just adding line spacing. You're adding half-leading on top of that reserved-metrics gap, which is invisible in a paragraph and glaring on a 64px headline that's supposed to sit flush against a nav bar.
line-height: 1 doesn't fix it either. It makes every line box exactly 1em tall — usually a bit less than the font's ascent + descent — but the glyphs are still positioned by those metrics, so the room for that Å is still baked in above the caps. You can watch this yourself: set a heading to line-height: 1 and put a border around it. There's still air above the cap-height, because 1 isn't "no leading," it's "exactly 1em per line" — and the font's ascent still sits well above its cap-height inside that 1em.
The property: text-box-trim
.headline {
font-size: 4rem;
line-height: 1.1;
text-box-trim: trim-both;
text-box-edge: cap alphabetic;
}
Or the shorthand, one line:
.headline {
text-box: trim-both cap alphabetic;
}
text-box-trim tells the browser which edge to cut: trim-start trims the top of the first line, trim-end the bottom of the last line, trim-both both. text-box-edge tells it what to trim to — cap alphabetic means "cut the top down to the cap-height, cut the bottom down to the alphabetic baseline," which is exactly the crop a designer means when they draw a box tight around a headline in Figma. Swap it for ex alphabetic and it trims to the x-height instead of the cap-height — useful for lowercase-heavy display text.
No font metrics to look up. No build step. No number that quietly goes wrong the day someone changes the typeface. The browser already knows its own font's metrics — this property just asks it to use them.
Toggle it live below: same headline, same line-height, one checkbox. Watch the box outline snap tight to the letters, and then drag the line-height slider and see the old negative-margin hack fall apart while text-box-trim keeps up on its own.
🎮 Try it yourself
▶️ Open the interactive playground →
Runs right in your browser — poke at it and watch the concept react live.
The one thing to check before you ship it
This is genuinely new. Safari shipped it first (18.2, December 2024), Chrome followed in 133 (February 2025), and Firefox caught up in 154 (August 2026) — so the latest version of every major engine has it, but anyone on an older browser won't. Check your support targets before you rely on it for anything load-bearing.
The good news is the failure mode is boring, not broken: on a browser that doesn't understand text-box-trim, the declaration is simply ignored and you get your normal line-height box back — the exact spacing you already ship today. Nothing shifts, nothing overlaps, no layout breaks. That makes it a safe one to add now for the browsers that support it, with zero fallback code, while everyone else quietly keeps today's behavior until their browser catches up.
Stop guessing the number
The gap above your headline was never a margin bug. It was line-height reserving space for accent marks your text was never going to use, and for years the only fix was measuring a font's metrics by hand or pulling in a library that does it for you. text-box-trim and text-box-edge let the browser do what it already knows how to do — read its own font metrics — instead of you reverse-engineering them one -0.18em guess at a time.
Go check your own design system's headline component for a negative margin with a comment like /* fixes gap above heading */. I'd bet you've got at least one. What's the ugliest one you've shipped — and are you brave enough to paste the exact number in the comments?
🧠 Test yourself
Think it clicked? Take the 7-question quiz →
Instant feedback, a hint on every question, and an explanation for each answer — right or wrong.
📚 Read next
- You hand-edit headlines to avoid orphaned words.
text-wrap: balancedoes it natively. - Stop Writing Media Queries for Font Size
- The Search Highlight That Deletes Your Selection
🚀 Want more like this? Every guide, playground, and quiz lives on bestpractic.org — open it and sign up free so the next one finds you.
Thanks for reading! Let's stay connected:
- ⭐ GitHub — follow me and star the projects: github.com/parsajiravand
- 💬 Discord — join the frontend best-practices community: discord.gg/d9KRhuAwQ
- 📸 Instagram — frontend best practices, daily: @bestpractice___
Top comments (0)