Preload本应不阻塞渲染,为何示例中脚本需等字体下载后执行?
嘿,这个问题我之前也碰到过,是个很容易踩的preload误区,我来给你理清楚为什么会这样:
核心原因拆解
preload只是"预获取",不是"预解析"
你用rel="preload"只是让浏览器提前下载了那个字体样式表资源,但并没有立刻把它当成样式表来处理——直到onload触发后把rel改成stylesheet,浏览器才会开始解析这个样式表,这时候才会触发里面Roboto和Material Icons字体的下载请求。字体默认是阻塞性资源,且会延迟
window.onload
Chrome里字体默认的font-display值是block,这意味着浏览器会先隐藏文本,直到对应字体加载完成(避免FOIT,Flash Of Invisible Text)。更关键的是,window.onload事件的触发条件是所有页面关联资源(包括DOM、样式表、脚本、图片、字体等)全部加载完毕,所以哪怕页面已经显示了,只要字体还在下载,window.onload就不会执行。
验证与修复方案
如果你想让window.onload不用等字体加载完才触发,最简单的办法就是修改字体样式请求,加上font-display=swap参数,让浏览器先显示系统 fallback 字体,不阻塞渲染和window.onload:
<html> <head> <!-- 添加&display=swap,改变字体的加载策略 --> <link rel="preload" onload="this.rel = 'stylesheet'" as="style" href='https://fonts.googleapis.com/css?family=Roboto:400,100,500,700,900,800|Material+Icons&display=swap'> </head> <body> Hello <script> window.onload = function () { console.log('Loaded') } </script> </body> </html>
切换到慢速网络测试的话,你会发现:
- 页面会立刻显示用系统字体渲染的"Hello",不会空白等待
console.log('Loaded')会在页面基础资源加载完后立刻执行,不用等字体下载完成
另外补充个小知识点:如果你的需求是提前加载字体本身而非样式表,也可以直接preload字体文件,但需要拿到字体的具体URL(可以从开发者工具的网络请求里找),不过这种方式不如修改font-display来得便捷。
内容的提问来源于stack exchange,提问作者George Paouris

