手动提取首屏关键css极易遗漏媒体查询、伪类及动态样式,且页面结构变更即失效;推荐用critters等工具基于真实dom自动提取并内联至,确保首屏渲染不阻塞。

为什么 inline CSS 不能靠手动复制粘贴
手动提取首屏关键 CSS 容易漏掉媒体查询、伪类、动态插入的样式,更麻烦的是:页面结构一改,手写的 <style></style> 就失效。实际项目中,npm run build 后生成的 CSS 文件里混着整站样式,而浏览器只在首屏需要其中不到 10% 的规则——不自动化,就等于把 90% 的 CSS 当作阻塞资源加载。
- Chrome DevTools 的 “Coverage” 面板能标出未执行的 CSS,但它只反映当前视口和交互路径,无法覆盖响应式断点或 hover 状态
-
critical工具依赖 Puppeteer 渲染快照,但默认不处理@import、CSS-in-JS(如 Emotion)或 Shadow DOM 内样式 - 若页面含 Web Component 或动态
document.styleSheets注入,多数工具会直接跳过这些规则
用 critters 提取并内联,绕过 Puppeteer 陷阱
critters 不渲染页面,而是静态解析 HTML 和已知 CSS 资源,适合构建时集成,尤其兼容 Vite 和 Webpack。它不会误删 @media (min-width: 768px) 这类首屏可能触发的断点规则,也不会忽略 :hover(只要对应元素在首屏 HTML 中存在)。
- Webpack 用户加插件:
new CrittersWebpackPlugin({ preload: true }),自动把提取出的关键 CSS 插入,非关键部分转为<link rel="stylesheet" media="print" onload="this.media='all'"> - Vite 用户用
vite-plugin-critters,需确保build.rollupOptions.output.entryFileNames不混淆 chunk 名,否则 CSS 路径解析失败 - 遇到
CSSStyleSheet.insertRule is not a function错误,通常是服务端渲染(SSR)时 Node.js 环境缺少 DOM API,换用critters的render模式而非inline模式
提取后必须验证:首屏元素是否真被样式覆盖
提取完成不代表生效——常见问题是 CSS 选择器权重不足,或被后续 <link> 中同名规则覆盖。比如提取出 .header { color: #333 },但页面末尾又载入一个全局 reset.css 把 color 设为 inherit,首屏文字就变色异常。
- 打开 Chrome DevTools → Elements 面板 → 选中首屏任意元素 → 查看右侧 Styles 标签页,确认所有声明来源是
<style></style>块,而非外部文件 - 搜索控制台报错:
Failed to execute 'insertRule' on 'CSSStyleSheet',说明有 @keyframes 或 @font-face 被错误内联(这些应保留在外部 CSS 中) - 用 Lighthouse 的 “Eliminate render-blocking resources” 检查项验证:优化后,
renderBlockingResources数量应 ≤ 1(即只剩内联关键 CSS)
移动端首屏样式提取要额外处理 viewport 和字体加载
手机端首屏高度小,但常含 position: fixed 导航栏、弹窗遮罩层等“视觉上在首屏、DOM 中不在首屏”的元素,critters 默认不识别这类情况;同时,Web Font 加载延迟会导致 FOIT 或 FOUT,即使 CSS 提取正确,文字仍闪动。
- 给关键字体加
font-display: optional,并在 HTML 中用<link rel="preload" as="font" crossorigin>提前拉取 - 对 fixed 元素,手动在 HTML 中添加占位 class(如
<div class="nav-placeholder"></div>),再在关键 CSS 中定义其样式,确保提取器捕获 - 避免在关键 CSS 中使用
rem单位配合动态根字体大小(如 JS 修改document.documentElement.style.fontSize),此时应改用px或em固定值
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











