内联关键css(critical css)是解决移动端首屏加载慢最直接有效的方法,即提取首屏必需样式(如导航栏、标题等)并内联至html的标签中,避免渲染阻塞;其余非关键css需异步加载,同时注意按设备宽度分别提取、排除@font-face/@keyframes、配置html缓存策略。

移动端 CSS 加载慢,不是靠“压缩文件”或“换 CDN”就能解决的。真正卡住首屏的是 render-blocking 行为——浏览器必须下载、解析完 <link rel="stylesheet"> 才能开始绘制首屏内容。内联关键 CSS(critical CSS)是目前最直接、见效最快的破局点。
什么是 critical CSS?为什么不能只靠 preload 或 async
critical CSS 是指页面首次渲染(First Contentful Paint)所必需的那部分样式规则,通常只覆盖 顶部可见区域的组件:导航栏、标题、首屏按钮、轮播图容器等。它和完整 CSS 文件不同,不包含折叠区、弹窗、分页、暗色模式切换器等后续交互才用到的样式。
你可能会想:用 rel="preload" 或 loadCSS() 不就行了吗?不行。因为:
-
preload只提升下载优先级,仍需等待解析完成才能参与渲染 -
loadCSS()异步加载后,样式应用有延迟,首屏仍可能闪白或错位 - 两者都未解决「浏览器必须阻塞渲染直到关键样式就绪」这个根本问题
而内联 critical CSS 后,样式已随 HTML 一并到达,无需额外请求,浏览器可立即构建渲染树。
如何提取并内联 critical CSS
手动写 critical CSS 极易遗漏或过量,推荐用工具自动提取。主流方案有两类:
-
Penthouse:Node.js 工具,基于真实 viewport 截图分析 DOM + 样式匹配,输出精准;适合构建时集成(如 Webpack 插件penthouse-webpack-plugin) -
Critical(by Addy Osmani):支持 CLI 和 Node API,可指定width/height和include路径;注意它默认不执行 JS,对动态插入的 class(如className={`btn ${type}`})可能漏判
示例(CLI 方式):
critical https://yoursite.com/ --base ./dist --html --minify --inline > index.html
生成的 <style></style> 块应放在 末尾,紧邻 <link> 非关键 CSS 之前。不要用 !important 或内联 @import —— 它们会阻塞解析。
内联后如何加载剩余 CSS?避免 FOUC 和重复应用
内联 critical CSS 只是第一步。剩余样式必须异步加载,但要防止样式闪烁(FOUC)或两次应用导致的抖动。
- 用
loadCSS()动态插入非关键 CSS,并配合onloadCSS()回调移除占位<link media="only x">—— 这是官方推荐链路 - 避免在
里写<link rel="stylesheet" href="non-critical.css">,否则仍会阻塞 - 如果项目用 Vue/React,别把 critical CSS 写进组件 style block 里——SSR 时无法保证注入时机,应统一由构建流程注入 HTML 模板
- 注意:
<style></style>内联块体积建议控制在 ~14KB 以内(HTTP/2 下单帧限制),超大会拖慢 HTML 解析
容易被忽略的三个细节
很多人做完内联就以为万事大吉,结果在真机上还是慢。问题常出在这三点:
- 未排除
@font-face和@keyframes:它们虽不参与首屏布局,但若出现在 critical CSS 中,会触发字体下载或动画解析,反而增加主线程负担 - 响应式断点没处理:critical CSS 必须按目标设备宽度(如
375px)提取,而不是桌面宽度;多端项目需分别生成 mobile/tablet 版本 - CDN 缓存了旧 HTML:内联后 HTML 变更,但 CDN 仍返回带旧
<style></style>的缓存页,导致首屏样式失效。务必配置 HTML 缓存策略为no-cache或基于哈希的版本化路径
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











