extractCritical 返回空 CSS 主因是工具未获取真实首屏样式:默认不加载远程 CSS、路径错误、动态 class 未渲染、@import 未展开;需显式传入本地 CSS 字符串、限定分析范围(如 include: '#app')、确保 HTML 为 SSR 渲染后的完整快照。

为什么 SSR 项目里 extractCritical 经常返回空 CSS
不是代码写错了,而是工具看到的 HTML 根本没加载样式资源。extractCritical(来自 critters 或旧版 penthouse)默认不下载远程 <link rel="stylesheet">,一旦路径 404、缺 <base>、或 CSS 文件还没生成到 dist 目录,就解析不出任何规则。
更常见的是:SSR 渲染出的 HTML 含动态 class(比如 class="btn btn--primary is-loading"),但提取工具只看到模板里的 btn,漏掉 is-loading 对应的样式;或者 @import 没被 postcss-import 展开,整条规则直接跳过。
- 用
fs.readFileSync把本地 CSS 文件读成字符串,显式传给extractCritical的css参数,绕过路径解析 - 确保传入的 HTML 字符串已内联基础样式,或至少是本地可访问的完整快照(比如从
dist/index.html读取) - 加
pruneSource: true和include: '#app',限制分析范围,避免扫进node_modules里未用的样式
Vite/Next.js 中 critical 插件注入时机不对怎么办
典型现象是生成的 Critical CSS 里塞满 .modal-hidden、.user-dropdown--closed 这类根本不在首屏出现的规则。原因很实在:构建时 HTML 模板还没被组件真正渲染,插件只能看到原始字符串里的 class,没法知道哪些会在 hydration 前真实挂载。
- SSR 场景(如 Next.js、Nuxt)优先在
getStaticProps或generateStaticParams里用renderToStaticMarkup预生成真实首屏 HTML 片段,再喂给critters - 若必须构建时提取,限定范围:
include: 'body > #root'+pruneSource: true,并拆分样式:首屏专用critical.css单独import,其余走 lazy CSS - 禁用条件渲染的 loading skeleton——比如不要在 SSR 阶段用
{isLoading ? <Skeleton /> : <Content />},否则提取器看到的只是<Skeleton>的 DOM
内联后页面反而闪动(FOUC)更严重?
这不是 Critical CSS 的问题,是加载链冲突了。你把提取出的样式内联了,但原来的 <link rel="stylesheet" href="style.css"> 还在 DOM 里,浏览器先画一次内联样式,等外部 CSS 加载完又重绘一遍。更糟的是,如果内联块里混进了 @font-face 或 url(/img/hero.jpg),这些会同步触发网络请求,卡死 CSSOM 构建。
立即学习“前端免费学习笔记(深入)”;
- 必须从 HTML 中彻底移除所有被提取覆盖的
<link>标签,不能只靠内联就以为万事大吉 - 内联块里禁止出现:
@import、@font-face、任何含url()的声明;这些该留在非关键 CSS 中,用rel="preload" as="style"控制加载时机 - 非关键 CSS 推荐用
media="print" onload="this.media='all'",或更稳妥的rel="preload" as="style" onload="this.onload=null;this.rel='stylesheet'"
移动端首屏提取为什么总出错?
用宽屏尺寸(比如 width: 1300)提取后直接用于手机端,结果塞进一堆 @media (min-width: 1200px) 规则,体积虚高、命中率低,甚至导致移动端首屏文字重叠。工具不会自动适配设备,得你告诉它“当前首屏长什么样”。
- 移动端优先模拟真实视口:
width: 375, height: 667(iPhone SE)或width: 414, height: 896(iPhone 12) - 务必过滤掉
@font-face、@keyframes和display: none元素的样式——它们不参与首屏渲染,放进去只拖慢 TTFB - 内联 CSS 体积必须 ≤14KB(gzip 后),超了反而增加解析开销;检查方式:用
zlib.gzipSync(criticalCSS).length算真实体积


















