比@import快是因为前者并行下载、后者串行阻塞;但仅用不够,需内联关键css、异步加载非关键样式、按缓存粒度合理拆分,才能切断阻塞链路并精准分发。

高并发场景下,CSS加载慢不是因为“请求数太多”,而是关键路径被串行阻塞、缓存失效或首屏冗余样式拖累渲染。核心解法是切断阻塞链路 + 精准分发。
为什么比@import快,但还不够
@import在CSS文件里触发串行加载:a.css里@import "b.css",必须等a下载解析完才发起b请求,多层嵌套时首屏延迟直接叠加。而<link>是并行发起HTTP请求,但若所有CSS都放在里且体积大,仍会阻塞HTML解析和绘制。
- 真实瓶颈不在“并发数”,而在“关键资源链长度”——浏览器要等全部CSSOM就绪才能paint
- 即使HTTP/2支持多路复用,
@import仍无法绕过CSS解析时序限制 - 构建工具(如Webpack/Vite)对
@import无法做静态分析,导致tree-shaking、scope隔离、关键CSS提取全部失效
关键CSS必须内联,但别手写
首屏需要的样式(比如导航栏、主标题、按钮框架)必须在HTML里内联,否则LCP指标必然超标。但手动提取容易漏、难维护,且超过4KB会拖慢HTML传输。
- 用
critters(Vite插件)或critical(Webpack插件)自动提取above-the-fold CSS,生成<style></style>块注入 - 确保内联内容不含
@import、@charset等非法声明,否则解析失败 - 内联后,剩余CSS要用
<link rel="preload" as="style" onload="this.rel='stylesheet'">异步加载,避免阻塞
合并CSS不能一刀切,得看缓存粒度
合并能减少请求数,但若把admin/dashboard.css和home/index.css打包进同一个app.css,用户访问首页时就得下载后台专用样式,浪费带宽且降低缓存命中率。
- 应合并的是高频共用部分:
reset.css、utils.css、button.css等,输出为vendor.[contenthash].css - 路由级样式(如
/user/profile.css)必须单独chunk,配合动态import或loadCSS()按需加载 - CDN缓存策略依赖URL变更:Webpack设
filename: "[name].[contenthash:8].css",HTML用html-webpack-plugin注入,禁止用?v=1.2.0这种query参数
Brotli压缩和HTTP/2不是万能解药
开了Brotli、上了HTTP/2,不代表CSS加载就快了。如果单个CSS文件从200KB压到150KB,但仍是阻塞渲染的关键资源,LCP照样卡住。
- Brotli比Gzip平均再省15%体积,但前提是服务器/Nginx配置了
gzip off; brotli on;且响应头含Content-Encoding: br - HTTP/2多路复用缓解了请求排队,但不解决CSSOM构建耗时——复杂选择器、大量
@media嵌套、未优化的动画帧仍拖慢解析 - 真正见效的是删掉没用的规则:PurgeCSS需显式声明
content: ["./src/**/*.{js,ts,jsx,tsx}"],否则对className={styles[theme]}类动态名会误删
最容易被忽略的点是:CSS文件名哈希是否真和内容绑定。改了一行边框颜色,但app.css的hash没变,CDN还在返回旧文件——这比加载慢更致命,因为问题不可见。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











