rel="preload" 单独无法让 CSS 异步生效,仅预下载不解析应用;必须配合 onload 改 rel 或 media 切换才能避免阻塞,且需注意子资源加载瓶颈。

不能直接用 rel="preload" 让 CSS “异步生效”——它只负责提前下载,不自动应用;必须配合 JavaScript 或 media 切换才能真正避免阻塞。
为什么 rel="preload" 单独写没用?
浏览器看到 <link rel="preload" href="a.css" as="style"> 时,会高优先级下载该文件,但完全忽略其中的 CSS 规则,也不会触发解析或应用。它就像“悄悄把文件存进缓存”,等你手动告诉它“现在可以用”,它才开始起作用。
常见错误现象:
- 页面渲染了,但非首屏样式始终不生效
- 控制台没报错,Network 面板里能看到 CSS 已下载完成,但 Elements 面板里没加载对应规则
- 多次刷新后偶尔生效——其实是缓存干扰了判断,掩盖了逻辑缺失
-
as="style"是必须写的,否则浏览器不会按 CSS 的优先级和解析逻辑处理该资源 - 漏掉
onload回调,或回调里没改rel或media,就等于白 preload - 某些旧版 Safari 对
onload在link上的支持不稳定,需额外兜底
onload 方案:改 rel 最稳妥
这是目前兼容性最好、语义最清晰的做法,现代浏览器(Chrome 50+、Firefox 46+、Edge 79+、Safari 15.4+)均支持:
<link rel="preload" href="non-critical.css" as="style" onload="this.onload=null;this.rel='stylesheet'"> <noscript><link rel="stylesheet" href="non-critical.css"></noscript>
关键点说明:
- this.onload=null 必须放在最前,防止资源重用或重复插入导致样式被多次挂载(尤其在 SPA 路由复用场景下)
- <noscript> 不是可选项:JS 被禁用时,靠它兜底保证样式仍能加载(虽会阻塞,但功能不降级)
- 不要用 onreadystatechange 替代 onload——它无法区分加载成功/失败,在 Chrome 和 Safari 中已基本不可靠
media 方案:更轻量,但有隐藏风险
利用媒体查询欺骗浏览器“暂时不用这个样式”,实现无 JS 异步加载:
立即学习“前端免费学习笔记(深入)”;
<link rel="stylesheet" href="non-critical.css" media="print" onload="this.media='all'">
优点是无需 rel="preload",也不依赖 as 属性,兼容性覆盖到 IE9+。
但要注意:
- 如果用户真在打印页面,这段 CSS 会被应用,可能造成意外样式污染
- 某些构建工具(如 Webpack + MiniCssExtractPlugin)会把 media="print" 当作真实条件,误删或忽略该规则
- 若 CSS 内含 @import 或 @font-face,这些子资源仍会在 media='all' 后才开始拉取,可能挤占首屏带宽
非关键 CSS 的子资源才是真正瓶颈
即使你把 non-critical.css 延迟加载了,如果它内部写了:
-
@font-face { src: url('heavy.woff2') }—— 字体文件会在挂载后才发起请求,而它通常 1–2MB,严重拖慢 LCP -
.hero { background-image: url('hero-banner.jpg') }—— 图片若走高延迟 CDN,也会卡住交互就绪时间 - 又或者它
@import了另一个 CSS,形成二级阻塞链
这些子资源不会被 preload 提前抓取,除非你在 HTML 里单独为它们加 <link rel="preload" as="font"> 或 <link rel="preload" as="image">。很多人只优化了主 CSS 文件,却忽略了这一层依赖,结果性能提升不明显。


















