浏览器遇到<link rel="stylesheet">时暂停DOM构建和布局,直至CSS加载解析完成,以确保JavaScript调用getComputedStyle()等API时样式就绪;若关键CSS未就绪,页面卡住不绘制,表现为白屏。

为什么会让页面白屏
浏览器遇到 <link rel="stylesheet"> 时,会暂停 DOM 构建和 layout,直到该 CSS 下载、解析完成。这不是 bug,而是为了保证 JS 调用 getComputedStyle() 或测量元素尺寸时样式已就绪。哪怕 HTML 已下载完,只要关键 CSS 没到位,页面就卡住不画——表现为白屏。
常见现象包括:首屏内容延迟出现、Lighthouse 报“Eliminate render-blocking resources”、弱网下白屏长达 2–3 秒。
内联 Critical CSS 的三个硬约束
内联不是把一堆 CSS 塞进 <style> 就完事。真正起效需同时满足:
- 提取必须基于真实首屏 DOM:SSR 渲染后的 HTML 必须含实际 class(如
is-loading),否则工具(如critters)只看到模板里的btn,漏掉关键规则 - 体积控制在 1KB 内(非 gzip):超过 TCP 初始拥塞窗口(约 14.6KB gzip 后),会触发额外 RTT,反而拖慢 TTFB
- 禁止含
@import、@font-face、url():这些仍会发起同步网络请求,卡死 CSSOM 构建
示例错误写法:<style>.hero { background: url(/img/hero.jpg); }</style> —— 这张图会阻塞整块内联样式应用。
立即学习“前端免费学习笔记(深入)”;
非关键 CSS 必须移出阻塞链
内联 Critical CSS 后,原 <link rel="stylesheet"> 标签若还留在 HTML 中,浏览器会先画一次内联样式,等外部 CSS 加载完再重绘一遍,引发 FOUC 或更长白屏。
安全做法只有两种:
- 用
media="print"+onload切换:<link rel="stylesheet" href="theme-dark.css" media="print" onload="this.media='all'">,确保加载但不阻塞 - 用
rel="preload" as="style"+onload注入:<link rel="preload" href="modal.css" as="style" onload="this.onload=null;this.rel='stylesheet'">,注意href必须与后续<link rel="stylesheet">完全一致(大小写、路径都不能差)
千万别只写 preload 不配 stylesheet,也别对多个 CSS 文件都 preload——带宽竞争会拖慢真正关键的资源。
构建时提取 Critical CSS 容易误判的根本原因
Webpack/Vite 插件(如 critters)在构建阶段拿到的 HTML 是模板字符串,没经过组件真实渲染。它看到的是 <div class="modal"></div>,却不知道这个 .modal 在 hydration 前根本不会挂载,结果把整套弹窗样式都塞进内联块。
解决路径很直接:
- SSR 场景(Next.js/Nuxt):在
getServerSideProps或generateStaticParams阶段,用criticalCLI 对已渲染的 HTML 快照提取,而非依赖构建插件 - 纯 CSR 场景:基本无效——首屏 DOM 是空的,提取结果为空或严重误判;若强行用
ReactDOMServer.renderToString,必须禁用 loading skeleton 等条件渲染逻辑,确保服务端输出结构与首屏一致
验证是否靠谱的唯一方式:DevTools → Network → 勾选 Offline → 刷新。如果首屏文字、按钮、色块还能正常显示,说明提取对了;否则就是漏规则或体积失控。


















