根本原因其实很简单:浏览器压根没把这个 preload 请求当成字体来处理。要么是 as="font" 没写对,要么 crossorigin 属性漏了,再不然就是 href 和 @font-face 里的 src 路径对不上。这三个错误里只要犯一个,你写的 preload 就基本等于废了。 为什么字
Link Preload:快速加载关键字体资源
时间:2026-06-17
浏览:477
文章目录
根本原因其实很简单:浏览器压根没把这个 preload 请求当成字体来处理。要么是 as="font" 没写对,要么 crossorigin 属性漏了,再不然就是 href 和 @font-face 里的 src 路径对不上。这三个错误里只要犯一个,你写的 preload 就基本等于废了。

为什么字体 preload 写了但 FOIT/FOUT 还在
相信不少人都遇到过这种情况:明明在 HTML 里加上了 ,但打开页面时,字体还是一闪而过,FOIT 或者 FOUT 依然存在。问题出在哪?
第一个坑:as="font" 没写对。很多人以为随便写个 as="woff2" 就行了,或者干脆不写。但浏览器看到这种写法,直接把它当普通资源请求处理,根本不按字体逻辑来。
第二个坑:crossorigin 属性没写。哪怕字体和你的 HTML 文件是同一个域名,浏览器加载字体时也默认走的是匿名 CORS 模式。如果你漏了这个属性,浏览器把字体文件下载完,也不会把它缓存给 @font-face 用。这不是 Bug,是浏览器的安全策略。
第三个坑:href 路径不一致。这个最容易被忽略。你在 preload 里写的路径,必须和 @font-face 的 src 完全一样——包括协议、域名、路径,甚至连后面的查询参数(比如 v=2.1)都要一字不差。差一个字符,浏览器就不会复用缓存,等于白忙活。
怎么在开发者工具里验证呢?去 Network 面板里看字体请求:如果 Initiator 列显示的是 parser 而不是 preload,或者 Priority 是 Low,甚至状态是 cancelled,那基本可以确定没生效。
字体 preload 的最小可行配置怎么写
其实你不需要写一堆复杂的属性,只要够用就好。下面这个配置是我认为最干净且可靠的写法,专门针对 WOFF2 格式:
对应的 CSS 里,必须有一模一样的 @font-face 规则:
@font-face { font-family: 'Inter'; font-weight: 700; src: url('/fonts/inter-bold.woff2') format('woff2');}
这里有几个关键点:
- 带上
type="font/woff2"总归是好的,可以避免 MIME 类型探测失败。当然,前提是你的服务器能正确返回Content-Type: font/woff2。 - 不要在这个标签上加
onload或者任何 JavaScript 控制逻辑。字体不需要你手动“激活”,只要@font-face注册成功了,浏览器发现页面文字用到这个字体,自己就会去缓存里取。 - 如果你用了 CDN,那
href必须写完整的 CDN 域名(比如https://cdn.example.com/fonts/...),不能只写相对路径,否则跨域问题又得让你头疼半天。
哪些字体不该 preload
千万别犯这个错误:以为预加载就是把所有字重都来一遍的保险操作。事实恰恰相反,预加载是精准狙击,不是地毯式轰炸。你多 preload 一个文件,就多占用一次 TCP 连接,多消耗一次带宽,多挤占其他真正关键资源的优先级。
- 只预加载首屏立即需要用到的字体组合。比如正文用
font-weight: 400,标题用font-weight: 700,那你就只 preload 这两个 WOFF2 文件。其他的,等用到时再说。 - 避免预加载那些可能永远不会在首屏出现的变体,比如
italic、light、thin等。除非你的设计稿里首屏就用到了。 - 别给 Google Fonts 那种全家桶式的
family=Inter:wght@100..900做批量 preload。把它拆解成单个href,只选你真正会用到的权重。 - 如果字体 URL 是动态生成的(比如带时间戳或哈希值),必须确保它和
@font-face里的地址完全一致,不然缓存永远无法命中。
怎么确认字体 preload 真生效了
别光靠感觉,得动手验证。打开 Chrome 的开发者工具,去 Network 面板里看。重点盯住三列:Initiator、Priority、Time。
- 筛选条件设为
type: font,然后看Initiator这一列,找到preload字样。如果显示的是parser或script,说明预加载根本没走通。 - 看
Priority列,正常情况下应该是Highest(Chrome)或High(Firefox)。如果显示的是Low,那大概率是as写错了或者根本没写。 - 对比一下没加 preload 时这个字体的 Start Time。理想情况下,加了 preload 之后,请求发起的时机应该能提前 200–600 毫秒,尤其是在弱网环境下会更明显。如果时间变化不大,那可能是路径不一致,或者服务端没配 CORS 头(
Access-Control-Allow-Origin: *)。 - 最容易被忽略的一种静默失效:去请求的 Headers 标签页里看
Accept请求头,是不是font/woff2?响应头里Content-Type是不是也匹配?只要有一个不匹配,预加载的结果就白费了。
还有一个最隐蔽的坑:服务端返回了 302 重定向,或者设置了 Cache-Control: no-store。这样会导致预加载的结果无法被后续渲染复用,而且它不会报错,你只会看到字体反复被下载。这种静默失效往往是最让人头疼的。
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。