link rel="stylesheet" 在 head 中同步加载会阻塞 html 解析和首屏渲染,解决方法是提取关键 css 内联(≤3kb)、非关键 css 用 media="print" + onload 异步加载,并确保 tailwind 的 content 字段完整覆盖所有模板路径。

link rel="stylesheet" 在 中同步加载,会直接阻塞 HTML 解析和首屏渲染,哪怕只有 10KB,Lighthouse 的 First Contentful Paint 和 Speed Index 也会掉 300ms+ —— 这不是“慢”,而是“卡住不动”。解决它不靠压缩体积,而靠打破阻塞链。
为什么 link rel="stylesheet" 必须被处理
浏览器遇到 <link rel="stylesheet"> 时,会暂停构建 DOM,等 CSSOM 完全就绪才继续。Lighthouse 把这个行为算作「渲染阻塞资源」,且 HTTP/2 并发请求只缓解排队,不解除阻塞。第三方 UI 库(如 antd、element-plus)全量引入后,常有 85% 的 CSS 根本没在首屏用到,却强制下载+解析。
验证方法:打开 Chrome DevTools → More Tools → Coverage → 刷新页面 → 查看 .css 文件右侧的红色比例条。红色 = 下载了但没执行的 CSS,就是可裁剪或异步的部分。
拆出关键 CSS 并内联
只把首屏真正需要的样式(按钮、标题、导航栏等)提取出来,内联进 ,绕过网络请求。其余非关键 CSS 异步加载。
- 工具推荐:
critters(Webpack/Vite 插件)或penthouse(服务端生成),能自动从完整 CSS 中提取首屏用到的规则 - 手动提取时,注意包含伪类(如
:hover)、媒体查询(如@media (max-width: 768px))和 JS 动态触发的类(如.is-open) - 内联上限建议 ≤ 3KB;超过后,浏览器重排开销反而可能拖慢渲染
非关键 CSS 改用 media="print" + onload
这是最轻量、兼容性最好的异步加载方案,不需要改构建流程,也不依赖 JS 框架。
<link rel="stylesheet" href="critical.css" media="all"><link rel="stylesheet" href="non-critical.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="non-critical.css"></noscript>
media="print" 让浏览器先下载但不解析;onload 触发后切回 media="all" 才生效;<noscript></noscript> 是必须的降级,否则禁用 JS 的用户会丢失样式。
注意:onload 不是所有浏览器都支持(IE 不支持),但现代项目基本可忽略;若需兼容 IE,改用 rel="preload" + onload 脚本注入。
Tailwind 用户必须配准 content 字段
Tailwind 默认输出几 MB 的全量 CSS,不是框架问题,是你没告诉它“哪些文件里写了 class”。生产构建时,content 字段漏一条路径,就等于没优化。
- Next.js App Router 必须同时覆盖:
./app/**/*.{js,ts,jsx,tsx}和./src/components/**/*.{js,ts,jsx,tsx} - 用了
.mdx?必须显式加进content,否则里面写的text-blue-500全被当死代码删掉 - 动态 class 如
className={`p-${size}`}不会被扫描,要么用@apply封装成静态类,要么在safelist中写正则兜底 - 验证是否真生效:在任意组件里加个非法类名(如
bg-hotpink),build 后跑grep -c "bg-hotpink" dist/*.css,结果应为 0
真正容易被忽略的点是:开发时 TAILWIND_MODE=watch 会跳过裁剪,如果 CI/CD 里误带入该变量,产出的就是全量 CSS —— 表面体积小,实际全是冗余类。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











