critters不是提取CSS而是模拟浏览器构建CSSOM;它用JSDOM解析真实DOM并反向追踪首屏渲染所需规则,需满足SSR/预渲染、显式声明路由、主CSS平铺关键样式三个前提,否则提取为空。

critters 不是“提取 CSS”,而是模拟浏览器构建 CSSOM
它不靠正则匹配或 AST 扫描,而是用 JSDOM 加载构建后的 dist/index.html,解析出真实 DOM 树,再模拟浏览器执行 CSSOM 构建过程,反向追踪哪些 CSS 规则真正参与了首屏渲染计算。这意味着::hover、[open]、@media (max-width: 768px) 这类动态/响应式规则,只要在首屏 DOM 中被触发或匹配,就会被识别并保留。
Vite 中 critters 提取为空的三个硬性前提缺失
常见现象是装了插件却没生成 <style data-critters>,根本原因是 critters 没拿到可分析的首屏 DOM 快照。必须同时满足:
- 构建产物 HTML 的
<body>非空——需开启build.ssr: true或使用vite-plugin-prerender生成含内容的静态 HTML - 首屏路由被显式预渲染——如用了 Vue Router 异步组件,得在
prerenderRoutes: ['/']中声明,否则 critters 不知道该抓哪页 - 关键样式不能藏在
@import里——critters 不解析被 import 的 CSS 文件,所有首屏必需规则必须平铺进主入口 CSS
内联后 FCP 反而变差?位置、体积、残留 link 三者必查
critters 输出的样式必须放在 <head> 中 <meta charset> 之后首个位置,否则浏览器仍会阻塞渲染。另外:
- 内联体积建议 ≤ 1KB;超过会延长 TTFB,尤其对弱网用户
- critters 默认不移除原始
<link rel="stylesheet">,必须手动配置或借助vite-plugin-critters自动清理,否则浏览器先画内联样式、再重绘外链 CSS,直接导致 FOUC - 输出不含
type="text/css"——若手拼<style>标签,漏掉这个属性会让旧版 Safari 忽略内联样式
penthouse 是 critters 失效时唯一可靠的兜底方案
当项目无法开启 SSR 或预渲染(比如纯 CSR + 动态数据依赖),critters 必然失败。此时只能用 penthouse,但它不是构建期工具:
立即学习“前端免费学习笔记(深入)”;
- 必须提供真实可访问的 URL,如
http://localhost:5173/,不能只给 HTML 文件路径 - 超时设为
--timeout 60000不够,还得加--wait-for "window.__APP_READY__ === true"等 JS 渲染完成 - 输出是纯 CSS 字符串,你得自己包裹成
<style type="text/css">...</style>并注入 HTML
真正的难点从来不在“怎么调用工具”,而在于确保提取时刻的 DOM 结构,和用户打开页面那一刻看到的完全一致——critters 依赖构建快照,penthouse 依赖运行快照,状态稍有偏差,关键规则就漏了。


















