预加载样式表何时有意义(何时没有意义)
探讨预加载样式表进行网页性能优化的相关考量。

预加载样式表何时有意义(何时没有意义)
我经常遇到预加载的样式表以及围绕它们的大量错误信息。预加载资源(通常)会改变其优先级和计划下载的时间。 然而,就像我每天遇到的许多优化策略一样,大多数情况下预加载样式表并没有多大意义。 在本文中,我将探讨预加载样式表何时有意义,何时可能不是最佳选择。
预加载样式表的理念:
在深入讨论之前,让我们简要回顾一下预加载样式表的概念。样式表是渲染阻塞的。这意味着在样式表下载过程中,浏览器不会渲染页面,访问者看到的只是一个空白屏幕。
为了最大限度地减少下载样式表所需的时间,开发者有时会采用预加载样式表的方式。 预加载涉及提前获取关键资源,最大限度地减少在实际需要时加载它们的延迟。 这通常通过使用带有 rel="preload" 属性的 <link> 标签来实现。
案例 1:在声明样式表之前预加载它。
有时开发者出于一片热忱,试图通过在 HTML 中实际 CSS 声明之前预加载来最小化 CSS 影响。代码看起来像这样:
<link rel="preload" as="style" href="style.css">
<link rel="stylesheet" href="style.css">
这样做完全没有意义,最好的情况是不会拖慢页面!浏览器会读取 HTML 并开始按顺序加载页面上所有关键资源。这意味着,如果你删除预加载那一行,浏览器同样会发现样式表并开始下载。你只是多加了一行代码而已!但情况可能更糟。预加载的样式表比普通样式表的优先级更低。因此在最坏的情况下,你实际上会拖慢你的页面!
3 个预加载的样式表

3 个普通样式表

案例 2:使用 link header 预加载样式表。
这个想法很有趣。我们可以使用服务器 link 响应头来预加载样式表。代码看起来像这样:
这里的思路是让浏览器在开始解析 HTML 之前就将样式表加入下载队列。这是一个很好的想法,我欣赏想出这个方案的开发者的思维方式!但不幸的是,在实际场景中你从中获得的收益很小。我们说的只是几微秒的差异。这些结果相当令人失望,但别担心。我们可以利用这个思路做出一些真正的改进!
案例 3:使用 103 early hints 预加载样式表
这是唯一一个能真正改善你的 Core Web Vitals 指标的方案!为样式表发送 early hints 将改善 First Contentful Paint 和 Largest Contentful Paint 等指标。
103 early hint 响应头在实际的 HTML 响应之前发送。这意味着在你下载 HTML 的同时,浏览器也可以开始并行下载样式表。 最理想的情况是,当 HTML 下载完成时,样式表可能也已经下载完毕。这意味着这些样式表的渲染阻塞时间为零。在较慢的网络上,这种情况确实会发生!在较快的网络上,效果不那么明显,但在几乎所有情况下使用 103 early resource hints 仍然更快!
103 early hint 响应看起来与 preload link header 非常相似。要使用 103 early hints,你需要配置你的 Web 服务器或 CDN。
HTTP/1.1 103 Early Hints
Link: </style.css>; rel=preload; as=style一些 CDN(如 CloudFlare)允许你通过简单地设置 link preload header(如方案 2 中所述)来触发 103 early hint。
案例 4:预加载样式表以实现异步 CSS
一个众所周知的技巧是预加载样式表使 CSS 变为非渲染阻塞的,一旦加载完成就将其添加到页面中。这个想法很简单,代码如下:
<link
rel="preload"
href="style.css"
as="style"
它基于普通的预加载代码 <link rel="preload" as="style" href="style.css">,并添加了一个 onload 事件监听器 onload="this.onload=null;this.rel='stylesheet'",将链接更改为最终形式 <link rel="stylesheet" href="style.css">
这是另一个很有道理的想法。如果样式表不是渲染阻塞的,浏览器可以继续解析和渲染页面,而无需停下来等待样式表。 但是,请注意!
- 不要对可见视口中的 CSS 使用异步加载。这很可能会导致 Cumulative Layout Shift,从而导致糟糕的 User Experience。
- 权衡利弊。异步 CSS 很可能会导致页面不同部分的重新渲染。这将影响 Interaction to Next Paint 等指标。
案例 5:预缓存样式表
在少数情况下,我看到一些巧妙的方案试图为后续页面浏览预热缓存文件。虽然我赞赏开发这些方案时的热情,但请不要这样做!
这个想法很简单:在首页上,如果你愿意,你可以提前预缓存另一个页面的样式。比如说产品页面。在页面加载完成后的某个时刻,你可以预加载样式表以将它们添加到浏览器缓存中。
function preloadStylesheet(url) {
var link = document.createElement('link');
link.rel = 'preload';
link.href = url;
link.as = 'style';
document.head.appendChild(link);
}
window.addEventListener('load', function () {
preloadStylesheet('cart.css');
preloadStylesheet('shop.css');
});乍一看这似乎还不错。在任何产品页面上,cart.css 和 shop.css 现在都可用,不会再阻塞渲染了。但有几个理由不这样做!
- 有更好的方法,例如投机预渲染或使用 service worker。
- 你可能会浪费资源,而且权衡下来不值得!面对现实吧:如果预加载资源很容易,浏览器早就做得更好了。
- 这类方案难以维护,并且将来可能会在某个时候引发问题。
- 你需要预加载所有样式表,而不仅仅是几个。因为所有样式表都是渲染阻塞的,并且并行下载,仅一个样式表就可能产生与多个样式表相同的效果。
Stop debating in Jira.
Get a definitive answer on your performance issues. I deliver a granular breakdown of your critical rendering path.
- Definitive Answers
- Granular Breakdown
- Critical Path Analysis

