FOIT是浏览器主动隐藏文本等待字体加载,而非单纯加载未完成;font-display: swap通过立即用系统字体渲染、加载完无感替换来解决FOIT,但需正确写入@font-face块内且避免404、CORS或体积过大等问题。

FOIT(Flash of Invisible Text)不是字体没加载完就卡白,而是浏览器主动把文字藏起来等字体就绪——它默认行为就是“宁可空白也不用系统字体凑合”。
为什么 font-display: swap 能解决 FOIT
现代浏览器在解析 @font-face 时,会根据 font-display 属性决定如何处理字体加载期间的文本渲染。默认值是 auto(等同于 block),即阻塞期 + 交换期都较长,导致文字长时间不可见。
-
font-display: swap告诉浏览器:立刻用系统字体显示,等自定义字体加载完成再无感替换 - 必须加在
@font-face规则内部,不能写在font-family应用处 - Chrome 87+、Firefox 73+、Safari 14.1+ 均支持;IE 完全不支持,但 IE 本就不触发 FOIT(它直接 fallback)
@font-face 中 font-display 的写法与常见错位
错误写法:font-display 放在外部选择器里,或漏掉分号,或拼错属性名:
@font-face {
font-family: 'Inter';
src: url('/fonts/inter.woff2') format('woff2');
font-weight: 400;
/* ❌ 错误:font-display 缺失 */
}
<p>/<em> ❌ 错误:写在 font-family 使用处 </em>/
h1 {
font-family: 'Inter', sans-serif;
font-display: swap; /<em> 这个无效! </em>/
}
正确写法(必须嵌入 @font-face 块中):
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
立即学习“前端免费学习笔记(深入)”;
@font-face {
font-family: 'Inter';
src: url('/fonts/inter.woff2') format('woff2');
font-weight: 400;
font-display: swap; /* ✅ 必须在这里 */
}
swap 不生效的三个真实原因
即使写了 font-display: swap,仍可能看到 FOIT,常见实际原因:
- 字体文件本身 404 或 CORS 报错,浏览器根本没开始加载,自然不会触发 swap —— 检查 Network 面板里
.woff2请求状态码和控制台是否有CORS policy错误 - 字体文件体积过大(> 200KB),加载耗时远超浏览器交换窗口(通常 3s),此时浏览器会放弃等待并保持 fallback 字体,但用户感知仍是“文字突然跳变”,而非“不可见”
- CSS 文件被
rel="preload"提前加载,但字体文件未预加载,造成字体资源滞后 —— 可对关键字体加<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin>
font-display 其他取值的实际表现
除了 swap,还有几个值会影响 FOIT 行为,但多数场景不推荐:
-
block:最长阻塞期(~3s),之后才 fallback —— FOIT 最严重,仅适合 logo 字等极少数必须等自定义字体的场景 -
fallback:极短阻塞期(~100ms),之后立即 fallback,且后续加载完成也不替换 —— 文字永不跳变,但牺牲了品牌字体一致性 -
optional:只在字体缓存命中时使用,否则全程 fallback —— 适合低优先级装饰性字体,但对正文不适用
FOIT 的本质是权衡:swap 解决了“看不见”,但引入了“看得见却跳变”。真正难处理的,是字体加载失败后连 fallback 都不出现——那往往不是 font-display 的问题,而是路径、CORS 或声明语法错了。


















