配了八年字体,每次 fallback 都要靠计算器——Chrome 127 把 aspect ratio 这件事彻底原生化了

换字体的时候有没有遇到过这种情况:font-size 明明一样,视觉上却大了一号?

这不是你的错觉。Verdana 的 aspect value(x-height / font-size)是 0.58,Times New Roman 是 0.46。设 16px,Verdana 的小写字母实际只有 9px 高,而 Times New Roman 只有 7px——差了整整 2px,肉眼非常明显。

以前只有 Firefox 认真支持这个属性,Chrome/Safari 都爱答不理。Chrome 127 把这件事彻底变了:font-size-adjust 现在是全功能状态,而且迎来了两值语法。

核心问题:fallback 字体的大小失真

CSS font-family 按顺序找字体,找到哪个用哪个。第一个字体没加载完时,浏览器会用 fallback 渲染,而这个 fallback 和你的主字体看起来大小完全不同。

根本原因是每个字体的 aspect value 不一样。Aspect value = x-height(字母 “x” 的高度)/ font-size。Verdana 约 0.58,Georgia 约 0.46,Roboto 约 0.5——同一个 font-size,不同字体的小写字母高度差 10% 以上。

旧方案:手动计算校正值

在没有 font-size-adjust 的年代,你要自己算:

body {
  font-size: 16px;
}
.fallback-text {
  font-family: "Roboto", "Arial", sans-serif;
  font-size: 16px;
  /* Verdana aspect: 0.58, Arial aspect: 0.46
     校正: 16 * (0.58 / 0.46) ≈ 20px
     但这个值是硬算的,换字体又要重算 */
}

问题是:你不知道下一个 fallback 的 aspect value,动态字体加载更是无从算起。

font-size-adjust 的解题思路

font-size-adjust 的思路是:告诉浏览器用哪个度量标准来校准字体大小

单值语法(已有多年)

/* 告诉浏览器:按 x-height = 0.5 的比例校准 */
font-size-adjust: 0.5;

这意味着:实际渲染时,浏览器会让 x-height = font-size × 0.5。不同字体通过调整 font-size 来满足这个比例,从而视觉大小一致。

两值语法(Chrome 127 新增)

这是关键升级。现在可以明确指定用哪个度量:

/* 按 x-height(字母 x 的高度)校准,比例从字体本身读取 */
font-size-adjust: ex-height from-font;

/* 按大写字母高度校准 */
font-size-adjust: cap-height from-font;

/* 按数字 0 的宽度校准(适合等宽场景) */
font-size-adjust: ch-width from-font;

/* 按 CJK 水字宽度校准(适合中日韩字体混排) */
font-size-adjust: ic-width from-font;

from-font 关键字让浏览器直接读取第一个可用字体的度量值,不需要你手动查表。

实战:设计系统字体回退

:root {
  --body-font: "Inter", "Noto Sans SC", sans-serif;
  --base-size: 1rem;
}

/* 校准到 Inter 的 x-height 比例 */
body {
  font-family: var(--body-font);
  font-size-adjust: ex-height 0.5; /* Inter 的 x-height 约为 0.5 */
  font-size: var(--base-size);
}

/* fallback 字体自动校准到相同视觉大小 */
p, li, td {
  /* 不需要重复写 font-size-adjust,会继承 */
}

真实数据:Inter(aspect 0.52)→ fallback 到 system-ui(aspect 0.48)时,16px 会自动校正到约 17px(16 × 0.52/0.48),视觉大小几乎不变。

浏览器支持:终于到齐了

浏览器 单值语法 两值语法(ex-height 等)
Chrome 127+ 127+ ✅
Edge 127+ 127+ ✅
Firefox 3+ 92+
Safari 16.4+ 17+
Safari iOS 16.4+ 17+

全球覆盖率约 94%。给不支持的浏览器一个 fallback 即可:

body {
  font-family: "Inter", system-ui, sans-serif;
  font-size-adjust: ex-height from-font;
  font-size: 1rem;
}

/* 不支持的浏览器忽略 font-size-adjust,用原始 font-size */

三个坑

1. @font-face 自定义字体的 aspect value

from-font 只读取系统字体度量。如果你的 Web Font 没有内置正确的度量数据,用显式数字更可靠:

/* 自定义字体不知道 aspect,手动指定 */
font-size-adjust: ex-height 0.52; /* 测量 Inter 的 x-height 得来 */

2. 只影响 fallback,不影响主字体

font-size-adjust 只对不在首选位置的字体生效。如果你声明的 font-family 第一个就命中了,font-size-adjust 不起作用。这是设计逻辑,不是 bug。

3. 调整的是 font-size,不是 x-height 本身

font-size-adjust 的本质是:当字体 fallback 时,临时增大该字体的 font-size 使其 x-height 匹配目标值。如果你对文字容器高度有精确约束,需要额外注意。

三步下一步

  1. 测当前 fallback 情况:打开 DevTools Elements 面板,临时把 font-family 改成只有 fallback 字体,看文字大小是否明显变化。如果变了,就该上 font-size-adjust。

  2. 找到你的基准 aspect value:Chrome DevTools Font 面板可以量 x-height。找到主字体的 x-height / font-size 作为基准值。

  3. 加到全局:root { font-size-adjust: ex-height <你的值>; } 一行解决所有 fallback 字体失真问题。


Chrome 127 把 font-size-adjust 做成全功能,意味着前端工程师终于可以在生产环境里用它了。八年 CSS,用过的人不多,不是因为它没用,而是因为浏览器支持一直在拖后腿。现在腿没了。

评论区

0 条评论

登录后可评论。

阿柯·前端架构 13 阅读