FOIT是浏览器主动隐藏文本等待字体加载,而非单纯加载未完成;font-display: swap通过立即用系统字体渲染、加载完无感替换来解决FOIT,但需正确写入@font-face块内且避免404、CORS或体积过大等问题。
FOIT(Flash of Invisible Text)不是字体没加载完就卡白,而是浏览器主动把文字藏起来等字体就绪——它默认行为就是“宁可空白也不用系统字体凑合”。
现代浏览器在解析 @font-face 时,会根据 font-display 属性决定如何处理字体加载期间的文本渲染。默认值是 auto(等同于 block),即阻塞期 + 交换期都较长,导致文字长时间不可见。
font-display: swap 告诉浏览器:立刻用系统字体显示,等自定义字体加载完成再无感替换@font-face 规则内部,不能写在 font-family 应用处错误写法: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 块中):
立即学习“前端免费学习笔记(深入)”;
@font-face { font-family: 'Inter'; src: url('/fonts/inter.woff2') format('woff2'); font-weight: 400; font-display: swap; /* ✅ 必须在这里 */}
即使写了 font-display: swap,仍可能看到 FOIT,常见实际原因:
.woff2 请求状态码和控制台是否有 CORS policy 错误rel="preload" 提前加载,但字体文件未预加载,造成字体资源滞后 —— 可对关键字体加 <link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin>
除了 swap,还有几个值会影响 FOIT 行为,但多数场景不推荐:
block:最长阻塞期(~3s),之后才 fallback —— FOIT 最严重,仅适合 logo 字等极少数必须等自定义字体的场景fallback:极短阻塞期(~100ms),之后立即 fallback,且后续加载完成也不替换 —— 文字永不跳变,但牺牲了品牌字体一致性optional:只在字体缓存命中时使用,否则全程 fallback —— 适合低优先级装饰性字体,但对正文不适用FOIT 的本质是权衡:swap 解决了“看不见”,但引入了“看得见却跳变”。真正难处理的,是字体加载失败后连 fallback 都不出现——那往往不是 font-display 的问题,而是路径、CORS 或声明语法错了。