Finally removing the invisible space above and below text cleanly
Every line of text in a browser carries invisible space above and below the actual letters, a side effect of font metrics reserved for line spacing. With text-box-trim and text-box-edge, that space can be removed precisely, without the fragile negative margin tricks that had to be recalibrated every time a font changed.
Table of Contents
- 1. The problem: invisible space above and below every text block
- 2. Understanding font metrics: ascent, descent and cap height
- 3. Why design tools like Figma measure text differently than the browser
- 4. The text-box-trim property: trim-start, trim-end, trim-both
- 5. text-box-edge: cap, ex, text and alphabetic as reference lines
- 6. In practice: buttons with precisely centered text
- 7. In practice: headlines and hero sections without spacing offset
- 8. Fallback for browsers without support
- 9. Browser support and how it compares to older approaches
- 10. Summary
- 11. FAQ
1. The problem: invisible space above and below every text block
Anyone who has tried to center a headline or a button label perfectly knows the phenomenon: no matter how carefully padding and line-height are set, the text always looks a touch too high or too low. The cause is not the CSS itself, but the font, which reserves more vertical space per line than the visible letters actually need.
In typography, that reserved space is called leading and by default splits evenly above and below the line. In a single line of text inside a button or a short headline, that surplus quickly adds up to several visible pixels that read like incorrect centering, even though the CSS is technically correct. In the past, only negative margins helped, and they had to be re-measured for every font change.
2. Understanding font metrics: ascent, descent and cap height
Every font file ships its own metrics that the browser uses to calculate line height: the ascent (the height above the baseline up to the tallest ascender), the descent (the depth below the baseline down to the lowest descender), and the line gap, an extra buffer many type designers set generously so multi-line text does not feel cramped. Together these three values produce a font's default line height.
For single-line UI elements like buttons or badges, exactly this line gap buffer is unwanted, because it reserves space that is never visually needed. Cap height, the height of an uppercase letter like H, sits much closer to what the human eye perceives as the actual height of text. It is precisely this gap between technical line height and perceived text height that text-box-trim addresses.
3. Why design tools like Figma measure text differently than the browser
Design tools like Figma display a text frame by default very tightly around the cap height and baseline, without accounting for the font's full line gap buffer. A developer rebuilding a Figma design pixel by pixel therefore regularly finds that the browser text takes up noticeably more vertical space than the design file, even though font size and line height were copied identically. That is not a bug, but a fundamentally different measurement method.
Figma measures text using the font's bounding box values, which are often tighter than the CSS line height the browser is instructed to render. This discrepancy has long been one of the most common sources of design-to-development friction during handoffs. text-box-trim closes that gap by letting the browser align itself to the same reference lines design tools already use for their own display.
4. The text-box-trim property: trim-start, trim-end, trim-both
The text-box-trim property determines on which side of a text block the excess leading space is removed. The value trim-start cuts the space above the first line, trim-end cuts the space below the last line, and trim-both removes both at once. The default value none behaves as before and changes nothing about the familiar behavior.
It matters that text-box-trim only affects the outer edges of the whole text block, not the spacing between individual lines inside a multi-line paragraph. Line spacing within a paragraph therefore stays untouched, only the first and last visible edge of the block gets trimmed. That makes the property useful specifically for containers whose outer dimensions should match the text exactly, without hurting the readability of multi-line paragraphs.
/* Base syntax: remove leading above AND below */
.card-headline {
text-box-trim: trim-both;
text-box-edge: cap alphabetic;
}
/* Trim only above, e.g. when spacing to the next
element below is still desired */
.section-title {
text-box-trim: trim-start;
text-box-edge: cap text;
}
/* Shorthand: text-box combines trim and edge */
.hero-title {
text-box: trim-both cap alphabetic;
}
5. text-box-edge: cap, ex, text and alphabetic as reference lines
While text-box-trim defines which side gets trimmed, text-box-edge defines which reference line the cut is aligned to. The value cap cuts the top at the top of uppercase letters, ex cuts at the top of lowercase letters like x, and text follows the full text boundary the font defines, including accent marks.
At the bottom, alphabetic is the most common value, because it ends exactly at the baseline and deliberately excludes descenders like those on g or y. Both values are given as a pair, one for the top and one for the bottom, for example text-box-edge: cap alphabetic. If only one value is given, it applies to both sides equally.
/* Comparing different edge combinations on the same headline */
.edge-cap-alphabetic {
text-box-trim: trim-both;
text-box-edge: cap alphabetic; /* tightest, most precise cut */
}
.edge-ex-text {
text-box-trim: trim-both;
text-box-edge: ex text; /* slightly more generous, safer for accents */
}
/* For multi-language content with umlauts and diacritics,
"text" as the top edge is the safer choice */
.headline-de-fr {
text-box-trim: trim-start;
text-box-edge: text;
}
6. In practice: buttons with precisely centered text
Buttons are the classic use case, because their vertical padding is usually set identically top and bottom, yet the text still appears slightly shifted upward due to the leading overhang. With text-box-trim: trim-both and text-box-edge: cap alphabetic, the actual text height matches the cap height, so symmetric padding also looks symmetric, without any empirically guessed correction values.
The effect adds up especially on small UI elements like chips, badges or tab labels: even a one- or two-pixel difference stands out clearly at a 20-pixel line height. Teams maintaining a consistent design system can define the rule once for all interactive text elements and never need to manually re-tune it for every new button type again.
.btn {
display: inline-flex;
align-items: center;
padding-block: 0.625rem; /* identical top and bottom */
padding-inline: 1.25rem;
border-radius: 0.5rem;
background: #4a1d96;
color: white;
font-weight: 600;
}
.btn > .btn-label {
text-box-trim: trim-both;
text-box-edge: cap alphabetic;
}
7. In practice: headlines and hero sections without spacing offset
In large hero headlines with a tight line-height, the leading overhang stands out especially strongly, because font size scales the absolute pixel value of the surplus proportionally. A hero title at 64 pixels can carry several pixels of empty space above the first and below the last line, noticeably throwing off a page's vertical rhythm, particularly when the headline sits inside a tightly tuned grid system.
For multi-line headlines, trim-start on the topmost and trim-end on the bottommost visible text block is recommended, while spacing between the individual lines remains untouched. That preserves the readability of the multi-line text while the spacing to elements before and after aligns exactly with the visual text boundary instead of the font's technical line height.
.hero-headline {
font-size: clamp(2.5rem, 5vw, 4rem);
line-height: 1.05;
text-box-trim: trim-both;
text-box-edge: cap alphabetic;
margin-block: 0; /* no more compensation via negative margins */
}
.hero-headline + .hero-lead {
margin-block-start: 1rem; /* precise spacing without a leading buffer */
}
8. Fallback for browsers without support
Because text-box-trim is a comparatively new property, not every browser in active use supports it yet. Since the property is simply ignored in non-supporting browsers without throwing an error, the layout falls back at worst to the old, slightly more generous look, instead of breaking entirely. Progressive enhancement is therefore given automatically, without any extra effort.
Anyone wanting to minimize the visual difference between supporting and non-supporting browsers can additionally use @supports to check whether the property is available and only then apply small adjustments to padding or margin that would otherwise cause a double offset. For most UI elements, however, the native fallback is entirely sufficient without any extra CSS.
.btn-label {
/* Base padding for browsers without text-box-trim */
padding-block: 0.75rem;
}
@supports (text-box-trim: trim-both) {
.btn-label {
text-box-trim: trim-both;
text-box-edge: cap alphabetic;
/* tighter padding, since the leading buffer is already removed */
padding-block: 0.625rem;
}
}
9. Browser support and how it compares to older approaches
Support for text-box-trim and text-box-edge has already landed in modern Chromium and WebKit based browsers, while other engines are working on implementations. Before using it in production, it is always worth checking a current compatibility table, because support for a still-young property can change quickly.
Compared to older approaches like manually calibrated negative margins or JavaScript libraries that read font metrics at runtime, the native property offers three clear advantages: it works independently of the specific font, does not break when the typeface is swapped, and costs no extra computation in the browser, because the metrics are already known while the font is being rendered.
| Approach | Font-independent | Maintenance effort | Browser baseline needed |
|---|---|---|---|
text-box-trim |
Yes | Very low | Modern Chromium/WebKit engines |
| Negative margins by hand | No, remeasure per font | High | All browsers |
| JS library for metrics | Yes | Medium, extra dependency | All browsers with JS |
line-height: 1 as approximation |
No, imprecise | Low, but inaccurate | All browsers |
Mironsoft
Modern CSS, layout architecture and rendering performance
CSS that stays maintainable instead of breaking with every change?
We review existing stylesheets for specificity chaos and layout thrashing, then build a CSS architecture with cascade layers, custom properties and modern layout primitives that still makes sense after the tenth feature.
CSS Audit
Systematically uncovering specificity issues, cascade conflicts and unused selectors.
Architecture Refactoring
Introducing cascade layers, custom properties and design tokens cleanly.
Performance Tuning
Fixing layout thrashing, expensive selectors and rendering bottlenecks.
10. Summary
text-box-trim: The Essentials at a Glance
Core problem
Fonts reserve more vertical space per line than the visible letters need, appearing as empty space above and below the text.
Solution
text-box-trim: trim-both together with text-box-edge: cap alphabetic removes that surplus precisely, without guessing at negative margins.
Design connection
Figma and other design tools already measure text tightly around cap height, text-box-trim aligns browser rendering with design files.
Fallback
Non-supporting browsers simply ignore the property, an @supports block allows additional fine tuning when needed.