把多余的行内空白裁掉:text-box-trim 与 strut
字体度量那页量出来:一段文字的 content-area 常常比 font-size 高,而且上下还不对称(Win/HHead 比 Typo 多伸出的那截、加上 line-height 上下半分的
leading)。后果是——给按钮标签、卡片标题做垂直居中时,文字总像「浮」在盒子里,上下呼吸感不均;想靠 padding 手动配平,每换一款字体又得重调,因为每款字体的度量不一样。
这页讲怎么把这层「多出来的行内空白」裁掉,让文字盒紧贴字形的度量边(如 cap 顶 ~ baseline 底):其一,现代标准 text-box-trim / text-box-edge——一行 CSS,声明顶 / 底各裁到哪条度量线(text / cap / ex / alphabetic),2024 末才进 Chrome / Safari;其二,传统做法 ::before strut——用伪元素造一根「支柱」手动抵消半行距(css-tricks 称 basekick,ishadeed
对齐按钮标签的做法与此相同),不依赖新特性、可作 fallback。
这层空白从哪来见字体度量(content-area 为何比 em 高、上下为何不对称);leading 上下半分、strut 的机理在姊妹系列 inline-block · 行框 与
inline-block · ZWSP strut。语法以 MDN 的 text-box-trim / text-box-edge / text-box 与 CSS Inline Layout Level 3 校准。
1 · 把按钮标签上下的空白裁平
一个按钮,上下 padding 都设 16px。但字体的 ascent / descent 加上半行距,会在大写字母顶之上、baseline 之下各塞进一层额外空白——于是你设的 16px,视觉上变成更厚、且上下未必相等的边距,换字体还会变。叠加层画出内容区上 / 下内沿(灰虚线 = padding 内壁)、cap-line(玫红)、baseline(深线);readout 量 cap 顶 / baseline 到内壁的多余空白。切到 text-box-trim,这层空白被裁掉,padding 重新等于视觉边距。
2 · text-box-edge:顶和底各裁到哪条线
text-box-edge 取两个值——over-edge(顶裁到哪)与 under-edge(底裁到哪);text-box-trim 再决定裁哪端(trim-start / trim-end / trim-both)。合起来就是把行盒从默认的「ascent ~
descent」收紧到你指定的度量线之间。
| 关键字 | 用在 | 裁到哪条线 | 适合 |
|---|---|---|---|
text |
over / under | 字体的 ascent(顶)/ descent(底)——几乎等于不裁 | 想保留完整度量 |
cap |
over | 大写字母顶 cap-height | 全大写 / 标签 / 按钮 |
ex |
over | 小写 x 顶 x-height | 以小写为主的正文标题 |
alphabetic |
under | 字母 baseline(忽略 descender 伸出部) | 绝大多数西文场景 |
最常用的一组是 text-box: trim-both cap alphabetic:顶裁到大写顶、底裁到 baseline——文字盒正好等于「大写字母的视觉块」,放进按钮里你设的 padding 多少就是视觉边距多少。over 用 ex 适合小写为主的标题;under 一般保持 alphabetic,除非要把 descender(g
/ y 的尾巴)也算进盒子才用 text。
3 · 三种写法(从推荐到 fallback)
现代写法:一行简写即可,text-box 同时给出裁端与两条度量线,标签自动光学居中。
.btn { text-box: trim-both cap alphabetic; }
/* 等价 longhand */
.btn { text-box-trim: trim-both; text-box-edge: cap alphabetic; }
渐进增强:现代优先,老浏览器退回 strut。--trim-top / --trim-bot 由字体度量算出(SCSS mixin 或 JS),随字体而定。
/* fallback: basekick — 收掉行盒 strut, 再给标签负 margin 削掉 cap 以上 / baseline 以下的空白 */
.btn { line-height: 0; }
.btn .lbl {
display: inline-block; line-height: 1;
margin-top: calc(-1 * var(--trim-top));
margin-bottom: calc(-1 * var(--trim-bot));
}
@supports (text-box-trim: trim-both) {
.btn { line-height: normal; text-box: trim-both cap alphabetic; }
.btn .lbl { display: inline; line-height: inherit; margin: 0; }
}
basekick 的原理:这层多余空白本质是 leading 与字体 ascent / descent 撑出来的,line-height 把文字放在行盒正中、上下各塞半行距(见 inline-block · 行框)。basekick 的做法:把文字设成
inline-block,先用 line-height 收掉行盒的 strut,再给它上下各加一段负 margin,把 cap 以上、baseline 以下的空白削掉——削多少由字体度量算出(css-tricks 用 SCSS mixin 算,本页 demo 的「strut」选项用 JS 实测 cap / baseline 位置)。ishadeed 的按钮修法同源:插一个 vertical-align: middle 的伪元素当支柱抵消度量。效果都等同 text-box-trim。
4 · 什么时候用
需要文字盒紧贴度量边的场景都适用:按钮 / 标签 / chip 标签垂直居中、卡片标题去掉上方多余空白做 baseline 对齐、图标旁文字的精确对齐(配合 inline-block · ZWSP strut)。能用
text-box 就用它(一行、随字体自适应、无硬编码);要兼容旧浏览器再叠一层 ::before strut 做 @supports fallback。注意 text-box-trim 裁的是块的首 / 末行行盒,不改变行与行之间的
line-height——它解决的是「文字块上下的多余空白」,不是行间距。
5 · 相关链接
-
Aligning button labels——ishadeed.com · Ahmad Shadeed。本页第一节的出处:字体 leading 让按钮标签上下空白不对称、
padding跨字体调不平;给出 Messenger 的修正方法——插一个vertical-align: middle的::before伪元素当支柱中和度量,并指向未来的 leading-trim。 -
How to tame line-height in CSS——css-tricks.com · Caleb Williams。讲清
line-height把文字放进行盒正中、上下各半 leading;核心技巧 basekick 用::before负 margin +translateY抹掉多余空白做 baseline grid 对齐——本页 strut fallback 的蓝本。 - text-box · MDN——developer.mozilla.org。
text-box-trim+text-box-edge的简写:text-box: trim-both cap alphabetic;normal复位。 - text-box-edge · MDN——developer.mozilla.org。over-edge(
text/cap/ex)与 under-edge(text/alphabetic)的取值与含义。 - text-box-trim · MDN——developer.mozilla.org。
none/trim-start/trim-end/trim-both:决定裁块的首行顶、末行底还是两端;当前兼容性(非 Baseline)。 - CSS text-box-trim · Chrome for Developers——developer.chrome.com。Chrome 133 落地说明:为什么需要它、与字体度量的关系、按钮 / 标题居中与 baseline 对齐的实战示例。
- 字体度量——这层空白从哪来——playground · font-features。content-area 为何比 em 高、上下为何不对称(Win / Typo 三套度量);本页就是把那截多出来的空白裁掉。
- 姊妹系列:Inline 与 inline-block · 拆解——playground · inline-block。leading 上下半分、line box、strut、cap 对齐的机理在这里;本页的 strut fallback 与
::before支柱即源于其中的行框与 ZWSP strut 两页。