font-display不是开关而是策略声明,必须写在@font-face内,配合format()、preload、度量相近的fallback字体链才生效;漏写任一环节会导致swap闪烁、fallback失效或退化为foit。

font-display 不是“开了就快”,而是必须配对 preload、正确 @font-face 声明、fallback 字体链,否则 swap 会闪、fallback 会失效、optional 会退化成白屏。
font-display 必须写在 @font-face 内部才生效
浏览器只认 @font-face 规则里的 font-display,写在外部 CSS、<link> 标签或 JS 里全无效。常见错误包括:
- 复制代码时漏掉引号,比如写成
font-display: swap而不是font-display: "swap"(注意:部分浏览器接受无引号,但 Safari 要求严格) - 拼错值,如
swop、swap:、font-display: fallback;多了个分号——整条@font-face会被忽略,字体压根不加载 - 同一
font-family名下只给 Regular 加了font-display,Bold 和 Medium 没单独声明,结果粗体仍走默认auto行为,FOIT 复现 -
src里没写format("woff2"),Safari 和旧 Edge 直接跳过该规则,退回到阻塞渲染
swap 不等于“不闪”,它只是把 FOIT 换成 FOUT
font-display: swap 让系统字体立刻显示,等 Web 字体加载完再替换——但替换瞬间若两个字体的 x-height、字宽、行高不一致,就会触发布局偏移(CLS),表现为文字“突然下移”或“换行点突变”。这不是 bug,是度量差异。
- 中英文混排尤其明显:中文用
"PingFang SC"回退,英文用"Segoe UI",基线对不齐 - 必须配同类型 fallback 链,例如:
font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; - 关键场景(如标题、按钮文字)可加
size-adjust微调占位比例,如size-adjust: 102%,仅 Chromium 和 Safari 17.4+ 支持 - 别依赖“本地不闪=线上不闪”:iOS 17.6 和 Android 14 的系统字体回退行为不同,DPR 高的屏幕放大度量差
preload 是 font-display 发挥作用的前提
font-display 控制“怎么显示”,<link rel="preload"> 控制“什么时候开始下载”。不 preload,swap 的“替换窗口”可能拖到首屏渲染完成之后,用户已读完文案,字体才刚发起请求。
- 必须加
crossorigin属性,否则 Chrome 拒绝将预加载资源用于@font-face,导致双倍请求 -
as="font"和type="font/woff2"缺一不可,否则浏览器当普通资源处理,不提升优先级 - 只 preload 首屏真正需要的字重,比如标题用
Inter-Bold.woff2,正文用Inter-Regular.woff2,别一股脑 preload 所有字重 - 跨域字体路径(如 CDN)必须带
crossorigin,否则 iOS Safari 可能拒绝加载
fallback 比 swap 更适合多数中文首屏文本
对中文字体(尤其是未子集化的全量 WOFF2),font-display: fallback 是更稳的选择:500ms 内用系统字体渲染,超时后放弃加载,不阻塞布局也不强求替换。
- 它规避了 iOS Safari 对
swap的激进实现——延迟替换 + 渲染卡顿,在弱网下反而闪得更明显 -
optional在中文场景基本不可用:要求 100ms 内加载完成,3G 网络下几乎不可能;Safari 14.1 以下直接退化为block,白屏 3 秒 - 中文字体体积大,
fallback能防止因单个字重加载失败(如网络中断)导致整页排版崩溃 - 需确保每个字重都单独声明
@font-face并配font-display: fallback,不能只写一次
最容易被忽略的是:font-display 的效果高度依赖真实设备和真实网络。模拟器里不闪,不等于真机 3G 下不闪;Chrome 里 OK,不代表 Safari 17.5 下不白屏。上线前务必用真机 + Network Throttling + Layout Shift Regions 实测。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











