字体一加载就抖一下?CSS font-size-adjust 让回退字体自己对齐尺寸
自定义字体没加载出来的那一瞬间,你的页面会「抖」一下——不是网络慢,是回退字体和正主根本不是一个尺寸。CSS 里一直有个属性专门治这件事,叫 font-size-adjust。它以前只认小写字母高度,现在 Level 5 把它扩成了五档尺度,连中文字体都能对齐。
先把结论放前面:字体回退导致的布局抖动(CLS),不需要换字体、不需要改架构,一行 font-size-adjust 就能压掉大半。前提是你要选对「按哪个尺子对齐」。
问题:同一段文字,换个字体就胖一圈
网页字体(web font)没加载完时,浏览器只能先用回退字体顶上。麻烦在于,同样是 font-size: 16px,Verdana 的小写字母明显比 Times 大一圈:
- Verdana 的纵横比(x-height / font-size)约 0.55
- Times New Roman 约 0.45
- Georgia 约 0.48
差 0.1 是什么概念?16px 字号下小写字母高度差近 1.6px。一行看不出来,一整屏正文累积起来,就是文字块整体变高、按钮被往下推——Lighthouse 里那个红色的 CLS 就是这么来的。
真实案例里,一个营销页的 CLS 是 0.34,性能分只有 62。排查掉图片和广告位之后,罪魁祸首就是 Web Font 替换回退字体时的整段 reflow。修复后用指标对齐的回退字体,CLS 直接掉到 0.02;另一个站点的单次字体替换从 0.135 → 0.000。
方案:告诉浏览器「按哪个尺子对齐」
font-size-adjust 的语义是:不管实际用哪个字体,都让指定的那个度量等于 设定值 × font-size。规范里给出的计算公式很直白:
u = ( m / m′ ) × s
s:计算出的 font-sizem:你在font-size-adjust里设定的目标比例m′:实际用到的那款字体自己的度量u:最终调整后的字号
也就是说,浏览器会反过来缩放回退字体,让它的度量去贴合你指定的比例。
CSS Fonts Level 5 把这个属性从「只能调 x-height」扩成了 五档度量:
font-size-adjust: ex-height 0.53; /* 小写字母 x 高度,默认值 */
font-size-adjust: cap-height 0.72; /* 大写字母高度 */
font-size-adjust: ch-width 0.55; /* 字符 "0" 的水平宽度 */
font-size-adjust: ic-width 1.0; /* 汉字 "水" 的水平宽度 —— CJK 专用 */
font-size-adjust: ic-height 1.0; /* 汉字 "水" 的垂直高度 —— CJK 专用 */
最省事的写法是 from-font:让浏览器自己读取首选字体的度量,然后拿它去校准回退字体。
body {
font-family: "Inter", system-ui, sans-serif;
font-size-adjust: from-font; /* 首选字体加载不出来时,按 Inter 的度量对齐 */
}
最后一行的 none 是默认值,等于完全不调整。还有一点容易踩:如果同一个度量已经在 @font-face 里被 size-adjust 改写过,那么 font-size-adjust 计算时用的是改写后的值——两者一起用时,size-adjust 会被抵消掉,别以为它们在叠加。
为什么中文字体特别需要它
ic-width 和 ic-height 用的是汉字「水」(U+6C34)作为基准字。这个设计对中国开发者格外友好:中文排版里,回退链的首选字体常常是思源黑体 / 苹方,回退到系统默认宋体或 Arial,汉字块的整体尺寸差异比拉丁字母更明显——因为一个汉字占满整个 em 方框,度量稍有偏差,行高就整体变了。
给中英混排的正文加上:
.article-body {
font-family: "Noto Sans SC", "PingFang SC", sans-serif;
font-size-adjust: ic-width 1.0; /* 让回退字体的汉字宽度对齐首选字体 */
}
这里的 1.0 意思是:让汉字宽度严格等于 font-size(标准全角宽度)。选 1.0 是个稳妥起点,因为主流中文字体的全角字宽本来就接近 1em。
浏览器支持
- Chrome / Edge 127+
- Safari 17+(含 iOS)
- Firefox 3+(它是这个属性的老东家,最早实现;118 之后短暂移除,后来又补回)
- 移动端:Android Chrome 151 / Android Firefox 153 起
不支持的浏览器会把这条规则直接忽略,字号维持原样——属于纯渐进增强,不会把页面弄坏,这也是它比一整套餐 @font-face 度量覆盖更省心的原因。
落地建议
- 先量数据,再调值。用
font-size-adjust: from-font起步,让浏览器自己算;如果兼容性有顾虑,再手填首选字体的纵横比(Inter ≈ 0.53,Arial ≈ 0.52)。 - 中英混排优先用
ic-width,纯拉丁正文用ex-height。 - 和
size-adjust别叠着用,选一个即可,否则白忙。 - 改完用 Performance 面板复测 CLS,对齐对了,Layout Shift 条会明显变短。
一句话总结:字体抖动这件事,过去大家都靠 @font-face 手写一堆 ascent-override / descent-override / size-adjust 硬扛,现在一行 font-size-adjust 就能把「按哪个尺子对齐」说清楚。中文项目尤其值得试 ic-width——标准早就在那儿了,只是没人告诉你。
评论区
登录后可评论。