critical css 是首屏渲染必需的样式子集,需内联至 标签并置于 顶部,以避免因等待外部 css 导致白屏或 fouc;提取须基于真实设备视口模拟,随 html 构建自动更新。

什么是 critical CSS,为什么必须内联
页面首屏渲染卡顿、白屏时间长,八成是因为浏览器在等待外部 CSS 文件下载解析。critical CSS 就是把首屏(viewport 内)渲染必需的那部分样式,直接写进 <style></style> 标签里,跳过 HTTP 请求。它不是全部 CSS,也不是“压缩后的 main.css”,而是精准提取、严格限定范围的子集——漏了会样式错乱,多了会拖慢 HTML 体积。
常见错误现象:FOUC(Flash of Unstyled Content)、Lighthouse 报 “Eliminate render-blocking resources”、实测 FCP(首次内容绘制) > 2s。
怎么提取真正的 critical CSS(别用在线工具凑数)
在线生成器(如 Critical、Penthouse)容易过度提取:把 @media (min-width: 1200px) 下的导航栏样式也塞进来,但用户手机访问时根本用不到。正确做法是按真实设备+首屏视口模拟提取:
- 用 Puppeteer 或 Playwright 启动无头 Chrome,设置
deviceScaleFactor: 1+viewport: { width: 375, height: 667 }(模拟 iPhone SE) - 加载页面后执行
document.styleSheets遍历,结合getComputedStyle(el)和el.getBoundingClientRect()判定哪些规则实际参与了首屏元素渲染 - 过滤掉
@font-face、@keyframes、未匹配选择器、display: none元素的样式
示例关键逻辑(Node.js + Puppeteer):
const cssText = Array.from(page.styleSheets).flatMap(sheet => {
try {
return Array.from(sheet.cssRules || []).map(r => r.cssText);
} catch (e) {
return [];
}
}).join('\n');
内联位置和加载顺序不能错
critical CSS 必须放在 最顶部,且在任何 <link rel="stylesheet"> 之前。否则浏览器仍会阻塞渲染——哪怕你内联了,后面紧跟一个 <link href="main.css">,它还是会等这个文件下载完才继续。
典型错误写法:
<link rel="stylesheet" href="main.css"><style>/** critical **/</style>
正确顺序:
<style>/** critical **/</style><link rel="preload" href="main.css" as="style" onload="this.onload=null;this.rel='stylesheet'"><noscript><link rel="stylesheet" href="main.css"></noscript>
注意:onload 内联脚本需配合 rel="preload",避免阻塞;<noscript></noscript> 是降级保障。
缓存与更新:critical CSS 不是写一次就完事
HTML 模板变了、首屏 DOM 结构调整、字体或间距微调,都会让原有 critical CSS 失效。它必须随 HTML 构建流程自动重生成,不能手写维护。
可行方案:
- Webpack:用
critical-webpack-plugin,配置base和src指向构建后 HTML,每次 build 触发提取 - Vite:用
vite-plugin-critical,支持 SSR 场景下按路由生成不同 critical 块 - 服务端渲染(如 Next.js):在
getStaticProps中调用critters库,传入 HTML 字符串实时提取
最容易被忽略的一点:提取时的 HTML 必须是最终上线版本——含真实 CDN 路径、环境变量注入后的结果。用开发环境 HTML 提取,上线后常因路径/类名哈希变化导致样式丢失。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











