内联 critical css 是唯一能将 fcp 压至 300ms 内的手段,其他方案仅加速下载;extractcritical 失败主因是未解析远程样式、动态 class 漏扫或 @import 未展开;需显式传入 css 字符串、移除冗余 link 标签、禁用内联块中的 @import/url()。

内联 critical CSS 是目前唯一能真正绕过 render-blocking、把 FCP 压到 300ms 内的手段;其他方案如 rel="preload" 或 loadCSS() 都只是加速下载,无法避免浏览器等待样式解析完成才能渲染。
extractCritical 返回空或样式缺失怎么办
这不是代码写错,而是工具没看到真实样式。常见原因包括:
-
extractCritical默认不下载远程<link rel="stylesheet">,若路径 404、缺<base>或跨域,就解析不出规则 - SSR 渲染后的 HTML 含动态 class(如
class="btn is-loading"),但工具只扫描模板里的静态 class,漏掉运行时才出现的样式 -
@import没用postcss-import提前展开,critters直接跳过整条规则
实操建议:
- 用
fs.readFileSync把 CSS 文件读成字符串,显式传给extractCritical的css参数,绕过路径解析 - 确保传入的 HTML 字符串已内联基础样式,或至少是本地可访问的完整快照(比如用 Puppeteer 截图后生成的 HTML)
- 加
pruneSource: true和include: '#app',限制分析范围,避免扫进node_modules里未用的样式
为什么内联后反而 FOUC 更严重
不是 critical CSS 本身的问题,而是 DOM 里同时存在内联块和原始 <link rel="stylesheet">,导致浏览器先画一次、再重绘一次。
更糟的是,如果内联块里含 @font-face 或 url(/img/hero.jpg),这些会同步触发网络请求,卡死 CSSOM 构建。
实操建议:
- 必须从 HTML 中彻底移除所有被提取覆盖的
<link>标签——不能只靠内联就以为万事大吉 - 内联块里禁止出现:
@import、@font-face、任何含url()的声明;这些该留在非关键 CSS 中,用rel="preload" as="style"控制加载时机 - 非关键 CSS 推荐用
media="print"hack + JS onload 切换,或直接rel="preload" as="style" onload="this.onload=null;this.rel='stylesheet'"
Webpack/Vite 构建时提取不准的根源
典型表现是生成的 critical CSS 里塞满 .modal-hidden、.user-dropdown--closed 这类根本不在首屏出现的规则。
原因是构建时 HTML 模板还没被组件真正渲染,插件只能看到原始字符串里的 class,没法知道哪些会在 hydration 前真实挂载。
实操建议:
- SSR 场景(如 Next.js、Nuxt)优先在
getServerSideProps或generateStaticParams阶段提取,用真实渲染后的 HTML 快照 - 若用静态构建,需配合
prerender或ssg模式生成带真实 DOM 的 HTML,再喂给critical工具 - 移动端务必按真实视口提取:iPhone SE 用
width: 375, height: 667,iPhone 12 用width: 414, height: 896;宽屏尺寸提取后直接用于手机端,命中率低、体积虚高
最容易被忽略的不是怎么提,而是提完之后要不要删 <link>、要不要调缓存、以及是否混进了 url() —— 这些细节一错,critical CSS 就从加速器变成拖慢 TTFB 的累赘。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











