@apply本身不慢,但用错位置、方式或未配content会导致Tailwind JIT输出大量冗余CSS,使包体积暴涨、构建变慢;根本原因是它绕过PurgeCSS扫描,造成语义脱节与规则重复生成。

直接说结论:@apply 本身不慢,但用错位置、用错方式、没配 content,会让 Tailwind JIT 无条件输出大量冗余 CSS 规则,最终导致生产包体积暴涨、构建变慢——这不是“用了@apply就变差”,而是它绕过了 PurgeCSS 的按需扫描机制。
为什么@apply会导致 CSS 体积失控?
根本原因不是语法开销,而是语义脱节:
-
@apply text-red-500 hover:bg-blue-600;这行代码里,text-red-500和hover:bg-blue-600不会被 PurgeCSS 扫描到——它只认 HTML 中class="text-red-500"这种字面量 - 你写 10 个
@apply,每个含 4 个工具类 → JIT 就生成 40 条独立规则,不管这些类在 HTML 里是否真实出现过 - 如果该 CSS 文件路径没加进
tailwind.config.js的content字段,整个自定义类(比如.btn-primary)可能被 PurgeCSS 全盘删掉,但@apply里的原子类仍照常输出(因为 JIT 已提前展开) - 嵌套使用(如
@apply btn; @apply btn-primary;)或混用自定义类(@apply p-4 my-shadow;),会触发重复生成 + 不可预测的删减行为
哪些地方写@apply是安全的?
必须同时满足这四点,否则就是埋雷:
- 只写在
@layer components { }块内(不能在普通.css规则里、不能在@layer utilities里) - 引用的全是 Tailwind 原生工具类(
px-4、bg-blue-600),不能是其他自定义类(@apply btn-primary会报错) - 该 CSS 文件路径已明确加入
content配置,例如./src/styles/**/*.css - 不包含响应式前缀(
md:px-6)、状态修饰符(hover:bg-blue-600)或动态值(bg-[${color}])——这些必须留在 HTML 层
比@apply更轻、更可控的替代方案
多数场景下,直接在 JS/TS 里封装字符串变量,比抽成 CSS 类更简单、更透明:
立即学习“前端免费学习笔记(深入)”;
- 组件内复用:用
const cardBase = "p-6 bg-white border border-gray-200 rounded-xl shadow-sm";,然后className={cardBase} - 跨组件复用:导出一个
cn工具函数配合twMerge,支持条件拼接和冲突合并 - 真正稳定、高频、无状态的 UI 单元(如按钮变体),才考虑
@layer components+@apply,且必须确保复用 ≥ 3 次、命名语义清晰(.btn-primary而非.button-variant-3) - 避免跨文件拆分:把所有
@layer components集中在src/styles/components.css,而不是每个组件都建一个index.css
最常被忽略的一点:优化效果不取决于你写了几个 @apply,而取决于 content 是否真实覆盖所有类名使用位置。开发时样式正常、上线后消失,90% 是这个配置漏了——不是 JIT 有问题,是你没告诉它“去哪找”。



















