临界CSS是渲染首屏内容所必需的最小样式集合,必须内联到<style>标签中以避免外部CSS阻塞渲染、缩短FCP时间;仅包含首屏可见区域用到的样式,体积建议≤14KB,并需配合移除或延迟加载原<link>以防止FOUC和重复应用。

什么是临界CSS,为什么必须内联到 <style>
临界CSS(Critical CSS)是渲染首屏内容所必需的最小样式集合。浏览器在解析HTML时,遇到外部<link rel="stylesheet">会阻塞渲染,直到CSSOM构建完成;而把这部分关键样式直接写进<style>标签里,能绕过HTTP请求、立即生效,显著缩短FCP(首次内容绘制)时间。
注意:不是所有CSS都适合内联——只提取首屏可见区域(如导航、标题、首张卡片)用到的选择器,其余仍走外部文件。
- 工具生成的临界CSS通常含
@font-face、@media查询(仅限匹配首屏尺寸的)、以及带:hover等伪类的规则(需确认是否影响首屏交互) - 内联后总
<style>体积建议控制在14KB以内(避免触发HTTP/2流优先级降级或移动端TCP慢启动惩罚) - 若页面有多个模板(如商品页/列表页),需为每种视口+设备组合单独提取,不能复用同一份
如何用工具自动提取临界CSS并注入<style>
手动提取几乎不可行:DOM结构动态、媒体查询条件多、框架组件样式分散。推荐用Node.js工具链自动化处理。
主流方案是penthouse(基于Headless Chrome)或critical(封装了penthouse):
立即学习“前端免费学习笔记(深入)”;
npm install critical --save-dev npx critical https://yoursite.com/home --base ./dist --css ./dist/main.css --output ./dist/index.html --inline
关键参数说明:
-
--css:指定源CSS文件路径(必须是已构建完成的、压缩后的最终版) -
--width和--height:模拟首屏尺寸(如--width 1366 --height 768),不设则默认992×768 -
--inline:自动将提取结果插入HTML的<head>中,替换原有<link> - 若HTML含服务端模板语法(如
{{ title }}),先构建静态HTML再运行critical,否则会解析失败
内联后如何避免样式闪烁(FOUC)和重复应用
常见错误是保留原始<link rel="stylesheet">又内联了相同规则,导致样式被覆盖两次,或加载顺序错乱引发布局抖动。
- 必须移除或延迟加载原
<link>:用rel="preload"异步拉取完整CSS,并在onload时插入<link>,防止阻塞 - 内联
<style>应放在<head>最顶部,且不要加media="print"等条件(会失效) - 若使用CSS-in-JS(如Emotion),其
extractCritical方法返回的是cssText字符串,需手动拼入<style>,注意转义<、>、&字符 - 检查DevTools → Elements面板,确认
<style>标签内没有/*# sourceMappingURL=...*/这类source map注释(会增大体积且无意义)
服务端渲染(SSR)场景下怎么安全注入
Next.js、Nuxt等框架默认不支持运行时提取临界CSS,需在构建阶段预生成,或改用critters(专为SSR优化)。
以Vite + React为例,在vite.config.ts中配置:
import { critters } from 'vite-plugin-critters'
export default defineConfig({
plugins: [critters({
publicDir: 'dist',
preload: 'media',
// 只对HTML入口文件生效,避免误处理404.html等
include: ['index.html']
})],
})要点:
-
critters在构建后扫描HTML,调用Chromium提取,比critical更适配现代打包产物 - 若开启
gzip或brotli压缩,确保<style>内容也被压缩(Vite默认开启) - 动态路由(如
/posts/[id])无法预知所有URL,此时应退回到“最大公共临界集”策略,或放弃内联、改用media="print" onload="this.media='all'"技巧
临界CSS不是一劳永逸的优化项——组件库升级、首页改版、新增首屏动画,都会让原有临界集失效;每次发布前务必重新提取并验证Lighthouse评分。



















