font-display: swap 是最实用的字体加载策略,因其兼容性好、副作用可控;省略 font-display 会触发默认 block 行为导致 foit;preload 字体必须带 crossorigin 属性;woff2 是唯一需上线的格式;document.fonts.load() 不适合控制首屏渲染。

font-display: swap 是当前最实用、兼容性足够、副作用可控的字体加载策略,其他选项要么风险高,要么适用场景极窄。
为什么不能省略 font-display
浏览器对 @font-face 的默认行为是 font-display: auto,实际等同于 block:文字先隐藏约 100ms,再最多等待 3 秒加载字体,失败才 fallback。这对内容页就是 FOIT(Flash of Invisible Text)——用户盯着白屏或空白段落,不是 bug,是默认策略。
必须显式写,不能依赖“浏览器自己判断”。swap 是唯一能在不改 HTML、不写 JS 的前提下,让文本立即可见的方案。
- 漏掉
font-display→ 等同于block→ 首屏文字大概率白屏 1–3 秒 - 写了但值是
block→ 主动延长 FOIT,毫无必要 - 用了
optional→ 字体可能根本不会加载,适合装饰性标题,不适合正文
preload 字体必须带 crossorigin,否则请求被静默忽略
<link rel="preload"> 是唯一能在 HTML 解析阶段就触发字体下载的手段,但它对属性极其敏感:缺 crossorigin,哪怕字体同源,浏览器也直接跳过该请求。
正确写法只有一种组合:as="font" + type="font/woff2" + crossorigin(空值即可,crossorigin="" 或 crossorigin 都行)。
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
- 没写
crossorigin→ Network 面板里看不到请求,或 Priority 显示为lowest,说明没生效 - 写了
crossorigin但字体服务没配 CORS 响应头 → 控制台报CORS error,字体加载失败 - 只 preload 首屏确定用到的字重,比如
Inter-Bold.woff2,别把整套 variable font 全 preloaded
WOFF2 是唯一需要上线的格式,TTF/OTF/woff1 全部删掉
所有现代浏览器(Chrome 36+、Firefox 39+、Safari 10+、Edge 14+)原生支持 WOFF2,且压缩率比 TTF 高 30%~80%,尤其在中文字体子集化后更明显。
继续保留多格式,只会增加构建复杂度、CDN 缓存压力和 HTTP 请求数,没有任何收益。
- 服务器返回
.woff2文件时,必须带响应头Content-Type: font/woff2,否则 Safari 和旧版 Edge 拒绝解析 - 构建流程中用
pyftsubset或 Transfonter 生成子集,英文正文常用字符集可压到原体积 20% 以内 - 中文场景慎用全量子集化;若用户会输入搜索词,建议首屏加载基础字集 + 滚动后懒加载扩展包
document.fonts.load() 不适合控制首屏渲染
有人想“等字体加载完再显示内容”,于是用 document.fonts.load("16px Inter", "a") + .then() 控制 DOM 渲染。这会导致首屏完全阻塞,违背性能优化初衷。
这个 API 的合理用途是:检测字体是否已缓存、做加载失败降级、或配合动画触发时机,而不是作为渲染门控。
- 在主线程轮询
document.fonts.check()会吃掉主线程资源,影响滚动和交互响应 - 用
font-display: swap+ CSS 自然替换,视觉上更平滑,也不需要 JS 干预 - 如果真要监听加载完成,优先用
fontfaceobserver这类轻量库,它内部用Promise+setTimeout回退,比裸用document.fonts更健壮
真正难的是权衡:swap 带来的重排是否可接受、子集覆盖是否够全、preload 是否真的提升了 LCP。这些没法靠一套配置解决,得看真实用户设备和网络环境下的 Performance 面板数据。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










