font-display: swap 是实现字体回退的前提,它使浏览器先用系统字体渲染再替换,避免FOIT;@font-face中必须显式声明,仅对首个有效src生效,Safari 14.1+才完整支持。

font-display: swap 是回退生效的前提
不加 font-display: swap,浏览器默认会阻塞文本渲染(FOIT),等自定义字体加载完才显示文字——这时候根本没机会触发回退。加了它,浏览器才会先用系统字体撑开布局,等网络字体就绪后再替换,真正实现“加载失败也不卡住”。
-
@font-face规则里必须显式声明font-display: swap,CSS 中其他地方设置无效 - 只对
src列表中首个有效字体起作用;如果第一个是本地字体(local())且匹配成功,后续网络字体就不会加载,也谈不上失败回退 - Safari 14.1+ 才完整支持
swap,旧版 Safari 会降级为auto(即 FOIT),需留意兼容性底线
src 顺序决定回退链路,不是“随便写几个就行”
浏览器按 src 声明顺序逐个尝试加载,一旦某个来源成功解析并可用,就停止后续尝试。所谓“回退”,本质是前面的失败后自动启用下一个。
- 推荐顺序:
local()→url() woff2→url() woff→ 系统字体栈(靠font-family回退) -
local("PingFang SC")这类写法在非 macOS 下直接失败,但不会报错,只是跳过;别指望它跨平台兜底 - 避免把
url()放最前——万一 CDN 挂了,连本地字体都来不及试,用户直接看到空白或默认衬线体 - 系统字体栈要写全:比如
"-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto", "Helvetica Neue", Arial, sans-serif,少一个可能在某系统上掉进 Times New Roman
字体加载失败 ≠ 字体未定义,得靠 fontfaceobserver 或 load event 验证
浏览器不会主动告诉你“woff2 加载失败”,它只是默默跳到下一个 src。你看到文字正常显示,不等于你配的网络字体真的被用了。
- 打开 DevTools → Network,过滤
woff2,看是否返回 404/403/timeout;若没请求,说明被local()截胡或 CSS 未生效 - 用
document.fonts.load("1em 'YourFontName'")可检测字体是否可用,但注意:它只检查是否“可加载”,不保证渲染时真被选中 - 真实场景中更可靠的是监听
document.fonts.onloadingerror(仅 Chrome/Firefox),或用第三方库如fontfaceobserver的check()方法捕获失败
font-weight 和 font-style 不匹配会导致“明明写了却不用”
哪怕 @font-face 声明了字体名,只要页面元素的 font-weight: 600 和该字体文件实际支持的字重不一致,浏览器就会跳过它,转而用系统字体——这算隐性“加载失败”。
立即学习“前端免费学习笔记(深入)”;
- 每个
@font-face块必须明确写font-weight和font-style,且和字体文件内嵌元数据严格一致(可用fonttools ttfdump查看) - 不要依赖浏览器自动映射:比如声明了
font-weight: 500的字体,但元素设font-weight: bold,多数浏览器不会把它当 700 用,而是回退 - 同一字体家族不同字重建议拆成多个
@font-face块,而不是用font-weight: 400 700这种范围写法——后者兼容性差,且部分浏览器不识别
真正麻烦的不是配不配得上,而是配完了你以为它在用,其实早被绕过去了。查 network、看 computed font-family、比对 weight/style 值,三步缺一不可。



















