写了三年排版,每次调整字体大小都要重新算一遍负 margin——今天 Firefox 154 把这件事彻底原生化了
写了三年排版,每次调整字体大小都要重新算一遍负 margin——今天 Firefox 154 把这件事彻底原生化了。
对,说的就是 text-box-trim。这个 CSS 属性 Firefox 154 上周刚发布,但大多数前端团队可能还没注意到——因为它解决的那个问题,大家早就习惯了,习惯了到觉得那是理所当然的。
字体的「呼吸」问题
每套字体都有自己的上下留白。这部分空间是真实存在的,它被刻进字体的度量数据里。你写 margin-top: 24px,标题实际上不会距离上方元素 24 像素——字体自己的上边界要吃掉一部分。更要命的是,不同字体这套留白完全不一样,一行文字里混了两套字体?间距就彻底乱了。
这导致了一个几乎每个前端项目都有的代码:
.card-title {
margin-bottom: -0.2em; /* 这个数字是怎么来的? */
}
这个 -0.2em 从哪来的?量出来的。换了一套字体,或者 webfont 加载前后切换了 fallback 字体,这个数字就废了。大多数项目的代码库里,这段注释不存在,解释这段数字的文档也不存在,发现问题的人只能靠猜。
text-box-trim 就是来解决这个的。
三行 CSS,删掉整个 workaround
h1 {
text-box-trim: both;
text-box-edge: cap alphabetic;
}
text-box-trim 指定要裁掉哪一边——over、under、both 或者 none。text-box-edge 指定裁到哪个度量边界——cap height、ex height、alphabetic、ideographic……两者配合,CSS 直接告诉你:「这段文字的实际边界到这里为止」。
结果是:你在 CSS 里写的 margin: 24px,真正落在 24 像素。不需要负 margin,不需要 JS 量尺寸,不需要 font-metrics-api。
/* 之前:负 margin 续命 */
.card-title {
margin-bottom: -0.25em;
}
/* 之后:原生支持 */
.card-title {
margin-bottom: 1em;
text-box-trim: under;
text-box-edge: alphabetic;
}
而且它是声明式的,不是 hack——换字体、换字号、在 webfont 加载过程中切换 fallback,字号关系全部自动保持正确。
另一个被删掉的 pattern:列表序号
text-box-trim 之外,Firefox 154 还给了另一个礼物:sibling-index() 和 sibling-count()。
做列表动画时,需要「第几个」来算 stagger 延迟是常见需求。现在的做法通常是:
items.forEach((item, index) => {
item.style.setProperty("--i", index);
});
然后在 CSS 里:
.item {
animation-delay: calc(var(--i) * 80ms);
}
换句话说:列表的「视觉行为」由 JS 决定,而不是 CSS。
sibling-index() 把这件事还给了样式表:
.item {
animation-delay: calc((sibling-index() - 1) * 80ms);
}
item:nth-child(3) 的 sibling-index() 就是 3,从 1 开始计数,可以在 calc() 里直接用。同家族的 sibling-count() 返回同级元素总数,两者和 text-box-trim 一样,可以删掉一整个 JS 工作量。
能删多少代码?
根据 PeopleAreGeek 的分析,这两个 CSS 新特性在 Firefox 154 里出现,最直接的影响是:
可以删掉:
- 所有依赖字体度量算出来的负 margin(通常是
em单位,查文档都不知道为什么是这个数) - 所有用 JS 给列表元素注入
--i变量的循环代码 - 如果你的项目里用了
counter-reset/counter-increment配合 nth-child 做的序号功能,部分可以换成sibling-index()
这是浏览器原生帮我们删掉那些「大家都这么写所以我也这么写」的 legacy code。
下一步
Firefox 154 已在 2026 年 8 月 18 日发布稳定版,Chrome 和 Edge 目前尚未支持这两个属性。text-box-trim 和 text-box-edge 属于 Firefox 独有——如果你的项目面向多浏览器,用 @supports 做渐进增强即可:
h1 {
margin-bottom: 1em;
}
@supports (text-box-trim: under) {
h1 {
text-box-trim: under;
text-box-edge: alphabetic;
}
}
这可能是最近一段时间里,最值得写进设计系统的 CSS 新特性之一——因为它直接解决的是那种「每个人都遇到过但每个人都懒得修」的长期问题。
评论区
登录后可评论。