字体加载不优化,首屏文字就可能白屏3秒——这不是 bug,是浏览器默认行为
必须用 font-display 控制,再配合 preload 和 WOFF2,否则用户看到的就是 FOIT(文字消失)或 FOUT(文字跳动)。

font-display 必须显式设置,别信 auto
浏览器对 @font-face 的默认行为是 font-display: auto,这实际上等同于 block 策略:先隐藏文字大约100毫秒,然后等待字体加载,最多能等3秒,加载失败才回退到备用字体。对于内容型页面来说,这简直是灾难性的体验。
swap:最常用的策略,立即显示备用字体,自定义字体加载完成后立刻替换。需要注意的是,这可能会引起页面重排。fallback:给自定义字体一个大约100毫秒的加载窗口,超时后就永久使用备用字体。这个策略适合那些非品牌核心的文本。optional:只在字体缓存命中或网络极快的情况下才使用自定义字体。它非常适合装饰性的标题字体,能有效避免不必要的网络请求。- 关键提醒:千万别用
block,它等于主动制造FOIT;也不要省略font-display属性,因为省略就等于默认启用了block行为。
正确的写法示例:
@font-face {
font-family: "Inter";
src: url("/fonts/Inter.woff2") format("woff2");
font-display: swap;
}
preload 字体必须带 crossorigin,否则无效
是唯一能在HTML层面提前触发字体下载的手段。但是,如果漏掉了 crossorigin 属性,浏览器会直接忽略这个preload请求——即使字体文件是同源的也不例外。
那么,具体该怎么操作呢?
- 属性必须写全:
as="font"、type="font/woff2"和crossorigin一个都不能少。 - 只对当前页面导航中确定马上要用的字体进行preload,比如首屏的标题或正文字体。
- 要明确一点:preload并不能替代
@font-face,两者需要共存。preload负责提前获取文件,而@font-face负责声明和应用字体。 - 如何验证?在Chrome DevTools的Network面板里,正确配置的preload请求,其Priority会显示为
High,如果没看到,就说明配置有误。
正确的写法如下:
只上线 WOFF2,别打包 TTF/EOT/woff1
WOFF2格式已经得到了所有现代浏览器的原生支持(Chrome 36+、Firefox 39+、Safari 10+、Edge 14+)。它的优势很明显:体积比TTF格式小30%到80%,对于经过子集化处理的中文字体,压缩效果更显著。继续提供其他格式,只会徒增CDN缓存压力、HTTP请求数和项目构建的复杂度。
- 在构建流程中,使用
fonttools或web-font-generator等工具直接转换出WOFF2格式,并果断删除所有其他格式文件。 - 务必检查服务器响应头:.woff2 文件必须返回
Content-Type: font/woff2,否则部分浏览器会拒绝接收。 - 关于IE11:它已退出主流支持周期,不建议再为它保留EOT或TTF格式。如果真有强制需求,可以单独通过条件注释或Ja vaScript动态加载来处理。
- 这里有个隐藏的坑:字体路径错误、CORS拦截、404等问题发生时,如果使用了
font-display: swap,页面根本不会报错。这意味着,你需要通过其他手段来主动检测。
document.fonts.load() 是唯一能确认字体是否加载成功的手段
font-display 只控制渲染策略,并不提供加载状态的反馈。当CDN故障、路径拼写错误、跨域请求被拒绝时,用户永远看到的是备用字体,而你对此可能一无所知。
- 使用
document.fonts.load(“12px ‘Inter’”)来主动检测,它会返回一个Promise。 - 加载成功时,可以添加特定的CSS类来触发动画效果,或者上报埋点数据;加载失败时,则可以降级提示或切换回系统字体栈。
- 兼容性提示:该API在Safari 10+、Chrome 35+、Firefox 41+中得到支持,旧版浏览器需要先进行特性检测,然后做降级处理。
- 重要细节:不要只检测一次。因为即使字体加载失败,
document.fonts.load()返回的Promise也可能变为完成状态。所以,需要结合document.fonts.check()来判断字体是否真的可用。
一个简单的检测示例如下:
document.fonts.load(“16px ‘Inter'”).then(() => {
if (document.fonts.check(“16px ‘Inter'”)) {
document.body.classList.add(“fonts-loaded”);
}
}).catch(() => console.warn(“Inter font failed to load”));
说到底,真正卡住人的往往不是代码怎么写,而是当字体加载失败时,根本没人知道。font-display 让页面看起来“一切正常”,却巧妙地掩盖了资源链路实际断裂的问题。因此,监控和降级检测机制必须跟上,否则,所有的优化都只是自我安慰罢了。
