⭐ 推荐:社区规则条款 V1.0

如何优化 HTML 的字体加载:font-display 和 preload?但 preload 已有,字体相关可能新。

周末
周末 萌新站长
发布于 2026-10-16 11:59 ·3 浏览 ·0 回复
内容摘要

优化字体加载需同时配置 preload 与 font-display:preload 控制下载时机,font-display 控制加载完成前的显示;正文用 optional/swap、标题装饰用 fallback、图标用 block,首屏仅

字体加载优化的结论一句话:**用 <link rel="preload"> 决定「字体什么时候开始下载」,用 font-display 决定「字体没下载完时页面显示什么」**,两者职责不重叠,必须同时配。默认不做任何处理时,浏览器要等 CSS 解析完、DOM 构建碰到用字体的文本了才去请求字体,这中间 300ms 到 3s 的空白就是经典的 FOIT(文字不可见)问题。

font-display 的 5 个值分别是什么意思,该怎么选?

font-display 是写在 @font-face 里的一个描述符,它把字体加载过程切成「阻塞期 + 交换期」两段:阻塞期内文字不可见(隐身),交换期内先用兜底字体显示、字体到了再换。

  • auto:等于浏览器默认,Chrome/Firefox 实际行为接近 block,最不可控,别用。
  • block:阻塞期 3s + 无限交换期。3 秒内一片空白,LCP 直接崩,只适合图标字体这类不能出现错误字形的场景。
  • swap:阻塞期 0s + 无限交换期。文字立刻用系统字体显示,字体到了再替换。绝大多数正文字体的默认选择。
  • fallback:阻塞期 100ms + 交换期 3s。3 秒还没到就彻底放弃,本次访问不再换字体。适合「换了会很难看」的装饰性字体。
  • optional:阻塞期 100ms + 交换期 0s。100ms 内没下载完,本页就不换字体了(下载会被降级甚至放弃),下次访问命中缓存才用上。它对 LCP 和 CLS 最友好,适合非品牌强制的正文。

结论:**正文用 optional 或 swap,标题/装饰字体用 fallback,图标字体用 block,永远不要用 auto。**

preload 字体为什么必须写 crossorigin?

因为字体请求按规范一律走 CORS 模式,即使是同域字体也一样。<link rel="preload"> 如果没加 crossorigin,浏览器会认为它预加载的是另一个资源,结果就是字体被下载两次——一次是 preload 的无 CORS 版本(拿到后丢弃),一次是 CSS 里的 CORS 版本。

正确写法(放在 <head> 最前面,早于引用字体的 CSS):

<link rel="preload" href="/fonts/inter-var.woff2"
      as="font" type="font/woff2" crossorigin>

三个属性都有用:as="font" 让浏览器用正确的优先级和缓存分区、type="font/woff2" 让不支持 WOFF2 的浏览器直接跳过这次预加载、crossorigin 避免双下载。

结论:preload 字体的 crossorigin 是必填项,漏写会白下载一遍。

preload 加多少条才合适?

结论:首屏只 preload 1-2 个字体文件,多了反而拖慢。

每个 preload 都会占用带宽和连接,字体文件 WOFF2 压缩后单个通常 20-50KB,中文字体即使做了子集化也可能 100KB 以上。如果 preload 了 4 个字体文件,它们会和 CSS、LCP 图片抢同一个 HTTP/2 连接的带宽。

判断标准很简单:只 preload「首屏可视区第一屏文字真正用到、且文件名在 HTML 里能确定」的字体。斜体、粗体、第二屏才出现的字体交给 CSS 按需加载。另外 preload 后如果 3 秒内没用上,Chrome 控制台会报 "The resource was preloaded using link preload but not used within a few seconds",看到这条就说明 preload 多了或路径写错了。

字体替换引起的 CLS 怎么治?

结论:**用 size-adjust + ascent-override 把兜底字体的字形尺寸对齐到 Web 字体,CLS 可以压到 0.01 以内。**

做法是给系统兜底字体也写一个 @font-face,把度量覆盖成 Web 字体的值:

@font-face {
  font-family: "Inter Fallback";
  src: local("Arial");
  size-adjust: 107%;
  ascent-override: 90%;
  descent-override: 22.43%;
  line-gap-override: 0%;
}
body { font-family: "Inter", "Inter Fallback", sans-serif; }

size-adjust 缩放字形整体大小,三个 override 用百分比覆盖上行高、下行高、行间距。具体数值可以用 Malte Ubl 的 fontaine 或 Next.js 内置的 next/font 自动算,不用手推。这三个属性 Chrome 92+、Firefox 89+、Safari 17+ 支持。

还有哪些容易踩的坑?

  • 别用第三方 CDN 加载字体:多一次 DNS + TLS 握手,通常 100-300ms。自托管并配 Cache-Control: public, max-age=31536000, immutable。
  • 用 Google Fonts 时在 URL 加 display=swap:https://fonts.googleapis.com/css2?family=Inter&display=swap,并对 fonts.gstatic.com 做 preconnect。
  • 中文字体务必子集化:用 unicode-range 把全量字体拆成几十个分片,只下载页面用到的字符区间,能把 3MB 的字体压到几十 KB。
  • 只用 WOFF2:比 WOFF 小约 30%,现代浏览器支持率超过 97%,不需要再挂 WOFF/TTF 兜底。

总结一下:preload 提前发起请求解决「下载晚」,font-display: swap/optional 解决「下载慢时白屏」,size-adjust 系列解决「字体替换时跳版」,三者各管一段,缺一不可;首屏只 preload 1-2 个 WOFF2,crossorigin 不能漏。

本文转载自 GJ站长论坛,原文地址:https://www.gj0.com/thread-2178.html
转载请注明出处,版权归原作者所有。
—/ 5暂无评分
还没有评分,来打第一分吧

全部回复 0

还没有回复,来抢沙发~