字体文件必须走强缓存,配置Cache-Control: public, max-age=31536000, immutable,并配合内容哈希命名与大小写不敏感匹配,确保首次加载后跳过网络请求且更新即时生效。

字体文件该用强缓存还是协商缓存
字体文件必须走强缓存,且要带 immutable。它和 HTML 完全相反:HTML 必须每次验证更新,字体一旦发布就不该变——改了字形或字重,就该换新 URL(比如加 contenthash)。如果对字体用 no-cache 或 max-age=300,浏览器会在每次导航时重新拉取,FOIT(不可见文本闪烁)概率飙升。
关键点:
-
Cache-Control: public, immutable, max-age=31536000是最优配置,immutable告诉浏览器“这个 URL 永远对应同一份内容”,跳过后续的条件请求 - 不能只靠
max-age;没有immutable时,浏览器在某些导航场景(如后退/前进)仍可能发条件请求 - 服务端返回的
Content-Type必须和link[type]、@font-face[src]中声明的格式严格一致(例如font/woff2),否则进不了 font 缓存池
preload 和 @font-face 的 URL 必须字节级一致
哪怕一个字母大小写不同,或差一个查询参数,浏览器就认为是两个资源——preload 加载的进 font 缓存,@font-face 请求的却去走网络,导致重复下载、FOIT 复现。
常见不一致场景:
-
href="/fonts/Inter.woff2"vssrc: url('/fonts/inter.woff2')(大小写) -
href="/fonts/roboto.woff2"vssrc: url('/fonts/roboto.woff2?v=1.2')(多出?v=1.2) -
href="/fonts/roboto.woff2"但@font-face里写了url('/fonts/roboto.woff2#font')(多了 fragment)
建议统一用根相对路径(/fonts/xxx.woff2),构建时由工具自动注入 hash,不手动拼 query。
crossorigin 属性漏写或错配会直接废掉 font 缓存
即使同域,link[rel=preload][as=font] 也必须带 crossorigin,否则 Chrome/Safari 会丢弃已加载的字形数据,不存入 font 缓存区。而 @font-face 请求若没收到匹配的 CORS 响应头(Access-Control-Allow-Origin: * 或具体域名),同样无法复用。
实操检查项:
-
——crossorigin不能省略,也不写crossorigin="anonymous"(值为空即可) - Nginx/Apache 需为字体路径显式添加响应头:
add_header Access-Control-Allow-Origin "*"; - CDN(如 Cloudflare)若开启“压缩”或“优化”,可能剥离 CORS 头,需在缓存规则中排除字体路径或强制透传
怎么确认字体真进了 font 缓存
别只看 Network 面板有没有 preload 请求,重点验证三处:
- 刷新后,字体请求的 Status 显示
200 (from memory cache)或304—— 若是200但没括号说明,大概率没命中 - DevTools → Application → Cache Storage → 点开
Font Cache(Chrome 115+),搜索文件名,确认存在 - Network 面板筛选
Initiator = preload,看 Priority 是否为Highest;如果是Low,说明as="font"没生效或被忽略
最隐蔽的坑是:字体进了 HTTP Cache 或 Memory Cache,但没进 Font Cache —— 这时 @font-face 依然会重新 fetch,因为浏览器只从 Font Cache 读取字体数据。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











