每次写按钮里的文字都要手动调半天垂直居中——今天 CSS 把 leading-trim 这件事彻底原生化了

做过设计系统的都知道,文字和图标放在一起垂直居中这件事,看着简单,做起来全是坑。line-height 给的间距是按照字体 ascent 和 descent 算的,但文字的实际”顶部”是 cap height(字母高度),”底部”是 alphabetic baseline(基线),两者之间差了半个 leading。导致你用 vertical-align: middle 居中的文字,看起来永远偏下;按钮里文字和背景边框之间,总是有那么几像素说不清的空隙。

这个问题 CSS 一直没管,设计师只好在 Figma 里调”垂直微调”,前端只好写负 margin 或者 hard code 像素值来凑。

问题的根源:half-leading

排版里有个概念叫 leading(行间距),来自活字印刷时代用铅条分隔行距的做法。Web 上的 line-height 会把一半 leading 放在文字上方,一半放在下方。这就是为什么一个 line-height: 1.5 的文字容器,实际高度比字体高度多出 0.5 个行高,而这个多余空间分布在文字上下两侧,精确位置取决于字体自己的 metrics。

所以当你把一个 32px 高的图标和一行文字放在同一个 flex 容器里垂直居中,文字容器的高度是 font-size × 1.5,但文字的实际”占地面积”只是从 cap height 顶到底部基线。视觉上永远是偏下的。

text-box-trim 是什么

Chrome 133 / Edge 133 / Safari 18.2 引入了一对 CSS 属性,让你把这段 half-leading 精确裁切掉:

.heading {
  text-box-trim: trim-both;
  text-box-edge: cap alphabetic;
}

text-box-trim 选择裁哪边:trim-start 裁上方,trim-end 裁下方,trim-both 两边都裁。text-box-edge 选择裁到哪个字体度量线:cap 是大写字母顶部,ex 是小写字母 x 的高度,text 是字体 ascent,alphabetic 是基线。

最常用的组合是 trim-both cap alphabetic:上方裁到大写字母顶,下方裁到基线。这正好是文字在视觉上的真实边界。

也有简写形式:

.heading {
  text-box: trim-both cap alphabetic;
}

三个真实场景

按钮里的文字居中。 之前按钮内文字和背景之间的间距是玄学,padding 加减 1-2px 全凭眼睛调。text-box: trim-both cap alphabetic 之后,文字盒子的边界正好是大写字母顶和基线,视觉居中变得可计算,不再依赖 hard code 的像素值。

标题紧贴分隔线。 一个 h2 上面要压一条 1px 边框,之前加 border-top,文字和边框之间永远有缝。用 text-box-trim: trim-start 把上方 half-leading 裁掉,标题顶边直接贴到大写字母的顶线,分隔线看起来就是压在标题字上的。

多行文字两端对齐的视觉平衡。 多行文字最后一行如果是短词,视觉重心偏上,和上面行不一致。text-box: trim-both cap alphabetic 让每行文字的实际”占地面积”对齐到同一个度量标准,视觉重心更一致。

三个坑

不是所有字体都支持所有边缘值。 text-box-edge 的 over edge 可以是 textcapex,under edge 可以是 textalphabetic。但如果字体文件里没有某个度量信息,浏览器会 fallback 到 auto,效果可能不是你预期的。使用前用 Chrome DevTools 检查 computed style 里的实际值。

不能替代 line-height。 text-box-trim 裁掉的是 first/last line 上下边缘的 half-leading,不是行间距本身。两行文字之间的垂直间距仍然由 line-height 控制,不要指望用它来压缩多行文本的段间距。

多列布局里,trim 会应用到每一列。multi-column 容器里使用 text-box-trim,每列的首行和尾行都会各自 trim,这是 spec 设计的,但需要注意如果列内有跨列的 spanner 元素,行为可能不一致。

三步下一步

第一,打开 Chrome DevTools,选一个标题,加 text-box: trim-both cap alphabetic,打开 “Show rulers” 观察文字盒子的实际边界变化——这是理解这个属性最直接的方式。

第二,把这个属性引入你的设计系统里的原子类,比如 .heading-tight 之类的名字,让需要紧贴边框的标题直接加 class,而不是每个组件单独调 padding。

第三,给按钮和 Badge 这类组件试用 text-box: trim-both cap alphabetic,感受一下”图标和文字终于真正垂直居中了”是什么体验,然后把这个组合固化到你全局的表单基础样式里。

结论

如果你在设计系统里经常需要调文字和周围元素的垂直对齐关系,text-box-trim 值得现在就加到你的工具箱里。Chrome 133+ / Edge 133+ / Safari 18.2+ 的覆盖率在全球已经超过 75%,作为渐进增强使用几乎没有风险。唯一的代价是记住两个属性名的组合:text-box: trim-both cap alphabetic,下一次调按钮垂直居中的时候,你就知道不用再 hard code 像素值了。

评论区

0 条评论

登录后可评论。