critters更可靠因其内置lightningcss解析器,能准确识别首屏样式,而手写脚本难以覆盖media查询、@import、css变量等边界场景。

为什么直接用 critters 比手写脚本更可靠
手动解析 HTML、提取 <link rel="stylesheet">、调用 clean-css 或 lightningcss 压缩、再注入 <style></style> 标签——这套流程看似可控,实则极易在边界场景崩掉。比如遇到 media 属性为 (prefers-reduced-motion: reduce) 的样式表,或内联了 @import 的 CSS 文件,或使用了 CSS 自定义属性但未提供降级值,手写逻辑很难全覆盖。而 critters 内置了真实的 CSSOM 解析器(基于 lightningcss),能准确识别哪些规则实际参与首屏渲染,不是简单按文件切分。
实操建议:
- 用
critters的Critters类实例,传入{ publicPath: '/assets/' },它会自动解析<link>的href并拼出完整路径,不依赖当前工作目录 - 若构建产物中 CSS 路径含哈希(如
main.a1b2c3.css),确保critters运行时机在webpack/vite生成资源之后,否则找不到文件 - 对动态
import()加载的 CSS,critters默认不处理——这类样式不属于“初始 HTML 可见部分”,强行内联反而拖慢首屏
critters 在 Vite 中的正确集成方式
Vite 本身不提供服务端 HTML 重写能力,所以不能像 Webpack 那样靠插件直接改 index.html。必须配合 vite-plugin-html 或 vite-plugin-static-html,在生成最终 HTML 时注入内联 CSS。
常见错误现象:运行 vite build 后,index.html 里没出现 <style></style> 标签,或出现但内容为空。
原因通常是:
- 插件顺序错:把
critters插件放在vite-plugin-html之前,导致后者读不到已处理的 HTML - 忽略
build.rollupOptions.output.entryFileNames配置,使critters查找 CSS 文件时路径不匹配 - 未设置
crittersOptions: { preload: false },它默认会加<link rel="preload">,但 Vite 的index.html里没有对应<link>原始标签可替换
最小可行示例(vite.config.ts):
import { defineConfig } from 'vite'
import critters from 'critters/vite'
import html from 'vite-plugin-html'
export default defineConfig({
plugins: [
html({ inject: { data: { criticalCss: '' } } }),
critters({
// 关键:告诉 critters 从哪里读取生成的 CSS
publicPath: '/assets/',
// 关键:禁用 preload,避免找不到原始 link 标签
preload: false,
// 关键:指定输出变量名,与 html 插件 inject 对齐
inject: 'criticalCss',
})
]
})
Webpack 下绕过 html-webpack-plugin 的坑
很多项目升级 Webpack 5 后发现 critters-webpack-plugin 报错 Cannot read property 'compilation' of undefined,根本原因是该插件未适配 Webpack 5 的新 API 结构,且长期未维护。
替代方案是直接用 critters 库 + html-webpack-plugin 的 alterAssetTagGroups 钩子,但要注意:
-
alterAssetTagGroups触发时,CSS 文件尚未写入磁盘(只在内存中),必须用compiler.outputFileSystem.readFileSync读取,不能用fs.readFileSync - 如果启用
splitChunks,多个 CSS chunk 可能被合并,需检查htmlPluginData.assetTags.styles是否包含所有目标<link>,而不是只处理第一个 -
critters的process方法返回的是字符串,不是 Promise,别在钩子里await它
内联后必须验证的三件事
内联完成不等于优化成功。真正影响 LCP 的,是浏览器是否能在解析 HTML 时同步应用这些样式。容易被忽略的点:
- 检查最终 HTML 中
<style></style>标签是否出现在里,且位置在所有可能触发重排的 JS 之前(比如<script src="app.js"></script>上方) - 打开 Chrome DevTools → Network → Disable cache,刷新页面,看
index.html的响应体里是否有大段 CSS 字符串;同时确认原<link>标签是否已被移除 - 用
document.styleSheets在控制台执行,确认内联样式表的cssRules.length > 0,避免因语法错误(如漏写;或})导致整个<style></style>被浏览器静默丢弃
最麻烦的其实是 CSS 中的相对路径引用,比如 background: url(./img/icon.png)。内联后路径基准变成 HTML 所在路径,不是原 CSS 文件路径——这问题不会报错,但图片就挂了。要么全改用绝对路径,要么用 critters 的 assetPrefix 选项重写 URL。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











