Tailwind CSS 复用与自定义
为什么要做复用
直接把工具类写在 HTML 上很方便,但当一个按钮、一个卡片在多处出现时,重复写一长串类名既难维护又容易漏改。Tailwind v4 提供几种方式把样式收敛起来,本篇讲最常用的三种:@apply、@utility、@layer。
@apply 提取成普通类
@apply 让你把多个工具类「应用」到一个普通 CSS 选择器里,得到一个自定义的样式类。
@import "tailwindcss";
.btn {
@apply px-4 py-2 rounded bg-blue-500 text-white;
}
.btn:hover {
@apply bg-blue-600;
}
之后在 HTML 里只需要写 class="btn",就能拿到这一组样式。
<button class="btn">提交</button>
<button class="btn">取消</button>
适用场景与局限
@apply 适合把「已经存在于工具类里的组合」重命名成语义类,比如 .btn、.card、.tag。
它有几点限制:
- 只能套用 Tailwind 已有的工具类,不能凭空创造新行为
- 不支持写在媒体查询、变体里的条件逻辑,复杂响应式还是建议在 HTML 上写
- 过度使用会让 CSS 和 HTML 脱节,失去原子化的直观优势
经验法则是:组件级、反复出现的组合才提取,零散的样式留在 HTML 上。
@utility 定义全新工具类
@apply 只能复用已有工具类,而 @utility 用来定义一套全新的、可被响应式和状态变体使用的工具类。
@import "tailwindcss";
@utility text-balance {
text-wrap: balance;
}
定义后 text-balance 可以像原生工具类一样使用,并且支持变体:
<h1 class="text-balance md:text-2xl">一段需要平衡排版的标题</h1>
@apply 与 @utility 的区别
@apply是把已有工具类组合进一个普通类,生成的.btn不能用hover:、md:等前缀直接修饰(除非在 CSS 里单独写)@utility定义的是真正的工具类,天生支持hover:、md:、dark:等所有变体- 想做「语义组件类」用
@apply;想做「可组合的新原子能力」用@utility
@layer 控制层级
Tailwind 内部把样式分成了几个层:base、components、utilities。默认情况下,@utility 进 utilities 层,@apply 写的普通类需要你决定放在哪一层。
@layer components {
.card {
@apply rounded-lg border p-4 shadow;
}
}
@layer utilities {
.no-scrollbar {
scrollbar-width: none;
}
}
把组件类放进 components 层,能确保它优先级低于 utilities,这样在 HTML 上写工具类时仍能覆盖组件默认值。
组件化思路
结合上面三种手段,一个常见的工作流是:
- 用
@apply+@layer components沉淀项目组件类(按钮、卡片、标签) - 用
@utility补充框架没有的原子能力 - 用
@theme统一管理颜色、字体等令牌,组件类里引用主题变量
@import "tailwindcss";
@theme {
--color-brand: #4f46e5;
}
@layer components {
.btn {
@apply px-4 py-2 rounded bg-brand text-white;
}
.btn:hover {
@apply bg-brand/80;
}
}
这样既保留了主题集中管理,又让 HTML 保持简洁。