Tailwindcss 的 base / components / utilities 三条指令是什么?
Tailwind v3 的三条 @tailwind 指令对应 三个不同职责,不是同级概念。
- @tailwind base:Preflight 重置,抹平浏览器默认
- @tailwind components:复合组件类(
.btn),中间层 - @tailwind utilities:原子类,按需生成,最后输出
- 级联顺序:
base → components → utilities,后写的赢 - v4 变化:三条合并成
@import "tailwindcss",components 删
原则:重置写 base,复合组件写 components,原子类写 utilities。
一句话总结三者的差别
base 解决「默认样式在哪里」——浏览器想给 h1 加 24px、ul 加项目符号、button 加灰色凸起,Preflight 全抹掉。
components 解决「复合组件怎么复用」——你写一个 .btn-primary,多处复用,且能被 utility 覆盖。
utility 解决「样式由谁决定」——你写 text-2xl,就有 24px;你 没写的,产物里 就没有。
三个职责完全不同,经常被混在一起说,是因为它们都写在你 CSS 文件的开头:
@tailwind base; /* Preflight + 你写的 base 扩展 */
@tailwind components; /* 你写的复合组件类 */
@tailwind utilities; /* 原子类 + 你写的 utility 扩展 */
@tailwind base 干了什么
具体 Preflight 抹了哪些东西,之前 Preflight 是做什么用的? 已经写过,这里只点关键的:
- 全局
box-sizing: border-box—— 宽度算到 padding/border 内侧 - 清空
h1~h6、<p>、<ul>的 默认 margin —— 别再让某段莫名其妙多了 16px - 标题不自带字号字重 ——
font-size: inherit; font-weight: inherit,纯靠 utility 类喂 <img>/<svg>/<video>/<canvas>默认 block —— 修复 inline 元素底部的 3px 空白- 表单控件继承字体 —— Safari 那套不听话的样式被统一
base 层的本质是:清成白纸,让你从零画。
@tailwind base 和 Preflight 是两件事@tailwind base 是一条指令,告诉 Tailwind 输出 base 层;Preflight 是 base 层里默认注入的那一段重置样式。
两者通过 tailwind.config.js 的 corePlugins.preflight 解耦:
// tailwind.config.js
module.exports = {
corePlugins: {
preflight: true, // 默认值,Preflight 会被注入
// preflight: false, // 改成 false 关闭 Preflight
},
};
| 配置 | @tailwind base 输出 |
|---|---|
preflight: true(默认) | Preflight + 你的 base 扩展 |
preflight: false | 只有你的 base 扩展,无 Preflight |
什么时候关 Preflight?
- 项目已经用了
normalize.css/reset.css,不想被 Preflight 覆盖 - 想完全自己控制
box-sizing、默认 margin 等基础样式
@tailwind components 干了什么
这一层是「复合组件」的位置,典型用法是 @apply 把一堆 utility 收成一个语义化的类:
@layer components {
.btn-primary {
@apply bg-blue-500 text-white px-4 py-2 rounded;
}
.card {
@apply bg-white p-6 rounded-lg shadow;
}
}
然后源码里写:
<button class="btn-primary">提交</button>
<div class="card">...</div>
不写 components 行不行?行,只是你每次都要堆一堆 utility:
<button class="bg-blue-500 text-white px-4 py-2 rounded">提交</button>
components 这层的真正价值不是「少打字」,而是「让 utility 能覆盖」:
| 写法 | 同优先级覆盖难度 |
|---|---|
直接堆 utility (class="bg-blue-500...") | utility 自己跟自己冲突,得加 !important |
用 .btn-primary | 加 class="bg-red-500" 就能直接覆盖 |
@apply 把多个 utility 折成一个类名,折完之后这个类的优先级仍处于 components 层(中间),后来的 utility 还能覆盖。
@tailwind utilities 干了什么
跟 base 的「一次性重置」不同,utility 层是 Tailwind 真正的核心——也是它和传统类库拉开距离的地方。
Tailwind 是个构建时扫源码的 CSS 生成器:
<div className="flex h-full bg-blue-500" />
构建器扫到上面这行,才会产出:
.flex { display: flex; }
.h-full { height: 100%; }
.bg-blue-500 { background-color: rgb(59 130 246); }
你 没写的 类,产物里 就没有。v3 后期加上 JIT 之后这成了默认行为。
为什么 utility 永远能胜出——级联顺序的关键
这是最反直觉的一点:你写 class="bg-blue-500",CSS 里 Tailwind 的 utility 层居然是 最后输出 的,所以你不用写 !important。
v3 默认级联顺序(也是 base / components / utility 这三个 @layer 给你定义的优先级):
@layer theme, base, components, utilities;
后定义的层覆盖先定义的。也就是:
theme先输出base接着components然后utilities最后
CSS 是常规级联,后面胜出,所以你 永远不需要 给 utility 类加 !important。
反过来也成立——你写在 <style> 末尾、但 没 放进任何 @layer 的全局样式,会被 utilities 覆盖。这是新手最常踩的坑之一。
你写的样式放哪一层
@layer base {
h1 { @apply text-3xl font-bold; } /* 全局标题默认字号 */
body { @apply bg-white text-slate-900 dark:bg-slate-950; }
}
@layer components {
.btn-primary { @apply bg-blue-500 text-white px-4 py-2 rounded; }
.card { @apply bg-white p-6 rounded-lg shadow; }
}
@layer utilities {
.scrollbar-hide { /* ... */ } /* 自定义 utility 类 */
}
| 你要写的样式 | 放哪一层 |
|---|---|
元素默认外观(全局 h1 字号) | @layer base |
复合组件(.btn-primary、.card) | @layer components |
自定义 utility(.scrollbar-hide) | @layer utilities |
一个常见埋雷:末尾裸写 + !important
!important 撑场,通常是因为样式放错位置/* ❌ 这段写在 style.css 末尾,没进 @layer */
.my-title { font-size: 40px !important; }
!important 就像叫救护车——能救命,但不该是日常通勤方式。正确写法是把样式放对位置,让 Tailwind 自带的级联帮你解决。
/* ✅ 放进 utilities 层,跟 Tailwind 自己写的 utility 同优先级 */
@layer utilities {
.my-title { @apply text-[40px] font-bold; }
}
这种写法 仍然排在末尾(utilities 层),但写起来跟原生 utility 一样,语义一致,以后改字号直接用 [40px] 这种 JSX/HTML 调试友好的语法。
v4 把三条指令合并了
Tailwind v4 砍掉了 @layer components,理由是:组件类本质上还是 utility 的合集,真要复用用 @apply 写到 utility 层就够了。文件开头的三条指令也被 一条 @import 取代:
/* v3 */
@tailwind base;
@tailwind components;
@tailwind utilities;
/* v4 */
@import "tailwindcss";
我的项目目前用 v3,所以
@layer components还在。如果你升级 v4,这层会全失效,得用@utility重写。v4 的@theme跟@utility详细讲解见 Tailwindcss v4 的 @import / @theme / @utility 指令是什么?。
一句话总结
三条 @tailwind 指令的分工:
- base = 抹掉浏览器默认值
- components = 用
@apply折出可复用的复合类,能被 utility 覆盖 - utilities = 按需生成你写的原子样式,永远最后输出
- 自定义 base 放
@layer base,组件放@layer components,utility 放@layer utilities - 别在 CSS 文件末尾裸写样式然后用
!important撑场
记住这三条指令的顺序就够了。base → components → utilities——后写的赢。