非关键css必须通过media="print"+onload切换实现“先下载、后激活”,避免参与首轮cssom构建;默认link rel="stylesheet"因需完整cssom才能生成渲染树,故必然阻塞首屏绘制。

非关键 CSS 不内联、不删,但必须让它“不参与首轮渲染树构建”——这是零阻塞落地的唯一可行路径。
为什么 link rel="stylesheet" 默认卡住首屏
浏览器解析完 HTML 后,能立刻生成 DOM 树;但渲染树(Render Tree)需要 DOM + CSSOM 合并才能产出。只要任一 link rel="stylesheet" 没完成下载和解析,CSSOM 就算不完整,渲染树就停摆,页面白屏或只显示裸文本。
-
@import在 CSS 文件里再拉一次样式,是串行阻塞,比link多一层等待,实测拖慢 FCP 300ms+ - 即使把
link放在最末尾,它仍会阻塞首次绘制(First Paint),不是解析阻塞,而是渲染阻塞 - 没加
media属性的link默认按media="all"处理,浏览器认定它是关键资源,必须加载
用 media="print" + onload 实现非阻塞加载
核心不是不让它下载,而是让它“先下、后用”,绕过初始 CSSOM 构建阶段。
- 给非关键 CSS 加
media="print":浏览器立即开始下载,但不参与当前渲染树构建 - 监听
onload事件切换回media="all"或media="screen",激活样式 - 不要用
addEventListener('load', ...)监听link:IE 不支持,且部分 Chrome 版本中可能不触发 - 切换后建议强制一次重绘(如读取
document.body.offsetHeight),避免样式延迟生效
示例:
<link rel="stylesheet" href="non-critical.css" media="print" onload="this.media='all'">
rel="preload" + onload 组合的坑
rel="preload" as="style" 能提前下载 CSS,但它只是“下完就完”,不会自动插入 CSSOM —— 直接用 JS 动态插入 <style></style> 容易引发 FOUC 或样式错乱。
- 不能写成:
<link rel="preload" as="style" href="main.css" onload="document.head.appendChild(...)"> - 正确做法仍是走
media="print"切换路径,preload可作为可选优化(配合 HTTP/2 Push 或 CDN 缓存预热) - 如果硬要用
preload,务必确保插入时机在 DOM 就绪之后、且 CSSOM 插入前手动触发一次样式重计算
内联关键 CSS 的边界在哪
内联不是“把 main.css 塞进 <style></style>”,而是提取首屏真实用到的选择器,体积必须可控。
- 只保留首屏可见区域真正需要的规则:比如
.hero、.logo、.cta-button的尺寸、颜色、显示逻辑 - 体积建议 ≤10KB,实测超过 1KB 就会影响 TTFB(尤其弱网),更别说解析开销
- 绝对不用
@import包裹内联样式——它会让整个内联失效,退化为同步网络请求 - 工具(如
critters或critical)能辅助提取,但上线前必须人工验证:打开 DevTools → Elements → 检查首屏每个元素是否真有对应样式生效
真正难的不是知道该怎么做,而是判断哪些 CSS 算“关键”、哪些算“非关键”——这得靠真实设备+真实网络条件下的 LCP 元素分析,而不是开发机上点点鼠标就拍板。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











