约 8 分钟读完 · 更新于 2026-10-21 · 文中每条都能在下面的配套工具里动手验证
字体导致的「闪一下」只有两个来源:字体到达前文字不可见(FOIT),或者先用后备字体画出来、到达后整段替换(FOUT)。两者都不是 bug,而是 font-display 明确规定的行为。选哪个值,本质是在「早看到字」和「字形正确」之间二选一,不可能同时要。顺序上还有一件事比策略更靠前:先把字体文件变小。一个 5MB 的中文字体,无论 font-display 写什么,用户体验都不会好。顺序永远是先减字节,再选策略,反过来做只是把痛苦换个位置。
FOIT 期间浏览器把文字渲染成透明,用户看到的是占位但没有内容;FOUT 先画后备字体,字体到位后触发一次重绘,会引起 CLS,尤其当中文字体与系统字体的字宽差异大时,一行文字可能整体位移几个像素。中文还有一个额外成本:常用汉字 3500 个起,一套完整中文字体动辄 3-10MB,是拉丁字体的上百倍。所以中文站点讨论字体加载,第一优先级永远是减少字节,而不是调 font-display。
| 取值 | 阻塞时长 | 切换行为 | 适用场景 |
|---|---|---|---|
| auto | 由浏览器决定,通常接近 block | 按 UA 默认策略执行 | 不建议显式写,行为不可预测 |
| block | 约 3s | 3s 内文字不可见,之后用后备字体并无限期等待替换 | 品牌标题、字数极少且必须用指定字形 |
| swap | 0s | 立刻用后备字体,字体到达后替换 | 正文,希望首屏立刻可读 |
| fallback | 约 100ms | 极短阻塞,随后用后备字体,约 3s 内到达才替换 | 折中方案,减少二次重排 |
| optional | 约 100ms | 极短阻塞,首次加载没用上则本次不加载 | 非关键装饰字体,允许首访没有它 |
@font-face {
font-family: "InterVar";
src: url("/fonts/inter-var.woff2") format("woff2");
font-weight: 100 900;
font-display: swap;
unicode-range: U+0000-00FF, U+2000-206F, U+2190-21FF;
}
@font-face {
font-family: "Inter Fallback";
src: local("Arial");
size-adjust: 107.12%;
ascent-override: 90.49%;
descent-override: 22.43%;
line-gap-override: 0%;
}
body {
font-family: "InterVar", "Inter Fallback", sans-serif;
font-synthesis: none;
}把 5MB 的中文字体切成一百多个子集、每片 30-60KB,是目前的主流做法:CSS 里写上百条 @font-face,浏览器只为页面实际出现的字符下载对应分片。代价是构建复杂度上升,要扫描内容收集字符、维护切片方案、字体更新后全部重跑。另一个常被忽略的现实是授权:不少中文字体按嵌入方式或访问量收费,子集化并不等于免费商用。如果页面主要是正文和 UI 文案,系统字体栈的收益通常高于自托管中文字体,因为省掉的是整个下载链路而不只是几十 KB。还有一个常被混淆的细节:preconnect 只提前建立连接,不下载文件;真正要抢在解析 CSS 之前发起请求,只能靠 preload。
如果一个站点的品牌字体本身就是设计的一部分,自托管仍然值得,但要按代价付费。可行的组合是:只保留标题用的一个字重,拉丁字符单独切包,中文按 unicode-range 分片,配 font-display: swap,preload 唯一那个关键文件,再把 size-adjust 对齐到后备字体。这套组合能把首屏字体成本压到几十 KB、把 CLS 压到接近零,代价是维护成本:每加一种语言、每换一次字体,都要重跑子集化、重新测量度量、重新验证 preload 路径。系统字体栈的成本恰好是零,换来的是字形随平台漂移。两边的账都算清楚,再决定要不要付这笔钱。
PXBO 的选择是完全不用 webfont,整站只依赖系统字体栈,不加载任何字体文件。收益可以量化:0 个第三方字体请求、0 字体相关 CLS、没有 FOIT 或 FOUT 需要讨论,文字在 HTML 解析后立即以最终字形出现,也不存在 preload 与 crossorigin 的坑。代价是不同系统字形不同:macOS 走 -apple-system,Windows 落到 Segoe UI,字宽和行高会差几个像素,做像素级设计还原时不好对齐。对一个开发者工具站这是可接受的,用户在意的是输入框和结果,不是字体品牌;内容站或品牌站则未必能接受。这是取舍,不是唯一答案。
:root {
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
"Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB",
"Microsoft YaHei", sans-serif;
--font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo,
Consolas, "Liberation Mono", monospace;
}
body {
font-family: var(--font-sans);
font-synthesis: none;
text-rendering: optimizeLegibility;
}不够。swap 只是把阻塞降到 0,文件太大仍会长时间重排;先减体积再谈策略。
缺 crossorigin 属性。字体请求是 CORS 模式,preload 不带该属性时与真实请求不匹配。
可以。woff2 在主流浏览器全面支持,体积比 woff 小约三成,不需要再补 ttf 或 otf。
size-adjust 整体缩放后备字体的字形大小,ascent/descent-override 只改行框的上下度量,用来对齐行高。