Skip to main content

Tailwindcss 的 base / components / utilities 三条指令是什么?

· 7 min read

Tailwind v3 的三条 @tailwind 指令对应 三个不同职责,不是同级概念。

  1. @tailwind base:Preflight 重置,抹平浏览器默认
  2. @tailwind components:复合组件类(.btn),中间层
  3. @tailwind utilities:原子类,按需生成,最后输出
  4. 级联顺序:base → components → utilities,后写的赢
  5. 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.jscorePlugins.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-primaryclass="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——后写的赢

Reference

  1. Tailwind CSS Adding Custom Styles 文档
  2. Tailwind CSS v4 Upgrade Guide
  3. Preflight 源码