1. Core concepts
  2. Styling with utility classes

Core concepts

// title 不翻译 export const title = "Styling with utility classes"; export const description = "从受限的原子工具集中构建复杂组件。";

概述

你可以通过在标记中直接组合多个单用途展示类 (utility classes) 来使用 Tailwind 进行样式设置:

ChitChat

You have a new message!

<div class="mx-auto flex max-w-sm items-center gap-x-4 rounded-xl bg-white p-6 shadow-lg outline outline-black/5 dark:bg-slate-800 dark:shadow-none dark:-outline-offset-1 dark:outline-white/10">  <img class="size-12 shrink-0" src="/img/logo.svg" alt="ChitChat Logo" />  <div>    <div class="text-xl font-medium text-black dark:text-white">ChitChat</div>    <p class="text-gray-500 dark:text-gray-400">You have a new message!</p>  </div></div>

例如,在上述用户界面中我们使用了:

  • displaypadding 工具类(flexshrink-0p-6)来控制整体布局
  • max-widthmargin 工具类(max-w-smmx-auto)来限制卡片宽度并使其水平居中
  • background-colorborder-radius 以及 box-shadow 工具类(bg-whiterounded-xlshadow-lg)来设定卡片外观
  • widthheight 工具类(size-12)来设置徽标图片的宽度和高度
  • gap 工具类(gap-x-4)来处理徽标和文本之间的间隔
  • font-sizecolor 以及 font-weight 工具类(text-xltext-blackfont-medium 等)来为卡片文本设定样式

这种样式设计方式虽然与许多传统最佳实践相悖,但一旦尝试你会立刻注意到以下几个非常重要的好处:

  • 更快完成任务 —— 你无需为命名类名、选择选择器或在 HTML 与 CSS 文件间切换而浪费时间,从而更快实现设计。
  • 修改更安全 —— 增删单个工具类只影响当前元素,不必担心无意中破坏其他页面。
  • 维护旧项目更容易 —— 修改某个元素只需调整类名,而无需理解那些数月未碰的自定义 CSS。
  • 代码更便于迁移 —— 由于结构和样式聚合在一起,你可以轻松复制粘贴整段 UI 至不同项目中。
  • CSS 不会不断膨胀 —— 因为工具类高度复用,随着新功能增加,CSS 不会呈线性增长。

这些好处在小型项目中就十分明显,对于长期、大规模团队项目更是意义重大。

为什么不直接使用内联样式?

很多人最初会疑问,“这不就是内联样式吗?”在某种程度上确实如此 —— 你直接在元素上应用样式,而非先定义类名再通过类名设定样式。

不过,使用工具类相比内联样式具有很多优势,例如:

  • 在约束中设计 —— 内联样式中每个数值都有点“魔法数字”的感觉,而工具类基于预定义设计系统,更易构建视觉一致的界面。
  • 悬停、聚焦等状态 —— 内联样式无法为 hover 或 focus 等状态设定样式,而 Tailwind 的 state variants 可以轻松实现。
  • 媒体查询 —— 内联样式无法使用媒体查询,但 Tailwind 的 responsive variants 能轻松构建响应式界面。

该组件完全响应式,包含一个具 hover 和 active 样式的按钮,并且全由工具类构建:

Woman's Face

Erin Lindford

Product Engineer

<div class="flex flex-col gap-2 p-8 sm:flex-row sm:items-center sm:gap-6 sm:py-4 ...">  <img class="mx-auto block h-24 rounded-full sm:mx-0 sm:shrink-0" src="/img/erin-lindford.jpg" alt="" />  <div class="space-y-2 text-center sm:text-left">    <div class="space-y-0.5">      <p class="text-lg font-semibold text-black">Erin Lindford</p>      <p class="font-medium text-gray-500">Product Engineer</p>    </div>    <button class="border-purple-200 text-purple-600 hover:border-transparent hover:bg-purple-600 hover:text-white active:bg-purple-700 ...">      Message    </button>  </div></div>

用工具类思维设计

为悬停和聚焦状态设定样式

想要在悬停或聚焦时为元素设定样式,只需在相应工具类前加上状态前缀,例如 hover:bg-sky-700

将鼠标悬停在此按钮上查看背景色变化

<button class="bg-sky-500 hover:bg-sky-700 ...">Save changes</button>

这些前缀在 Tailwind 中称为 variants,仅在对应状态满足时才应用工具类样式。

下面展示了 hover:bg-sky-700 类生成的 CSS:

Generated CSS
.hover\:bg-sky-700 {  &:hover {    background-color: var(--color-sky-700);  }}

注意,该类仅在元素被悬停时生效,其唯一作用就是提供悬停样式。

这与传统 CSS 写法不同 —— 传统中一个类通常涵盖多个状态的样式:

HTML
<button class="btn">Save changes</button><style>  .btn {    background-color: var(--color-sky-500);    &:hover {      background-color: var(--color-sky-700);    }  }</style>

你甚至可以组合多个前缀以在多重条件同时满足时应用工具类,如同时使用 hover:disabled:

<button class="bg-sky-500 disabled:hover:bg-sky-500 ...">Save changes</button>

更多内容请参阅 hover, focus and other states 文档。

媒体查询与断点

与 hover 和 focus 状态类似,你可以在工具类前添加断点前缀,为不同屏幕尺寸设定样式:

调整窗口大小查看布局变化

01
02
03
04
05
06
<div class="grid grid-cols-2 sm:grid-cols-3">  <!-- ... --></div>

上例中,sm: 前缀确保 grid-cols-3 仅在 sm 断点及以上生效(默认 40rem)。

Generated CSS
.sm\:grid-cols-3 {  @media (width >= 40rem) {    grid-template-columns: repeat(3, minmax(0, 1fr));  }}

更多内容详见 responsive design 文档。

针对深色模式设定样式

在深色模式下设定样式,只需在工具类前加上 dark: 前缀:

Light mode

Writes upside-down

The Zero Gravity Pen can be used to write in any orientation, including upside-down. It even works in outer space.

Dark mode

Writes upside-down

The Zero Gravity Pen can be used to write in any orientation, including upside-down. It even works in outer space.

<div class="bg-white dark:bg-gray-800 rounded-lg px-6 py-8 ring shadow-xl ring-gray-900/5">  <div>    <span class="inline-flex items-center justify-center rounded-md bg-indigo-500 p-2 shadow-lg">      <svg        class="h-6 w-6 text-white"        fill="none"        viewBox="0 0 24 24"        stroke="currentColor"        aria-hidden="true"      >        <!-- ... -->      </svg>    </span>  </div>  <h3 class="text-gray-900 dark:text-white mt-5 text-base font-medium tracking-tight ">Writes upside-down</h3>  <p class="text-gray-500 dark:text-gray-400 mt-2 text-sm ">    The Zero Gravity Pen can be used to write in any orientation, including upside-down. It even works in outer space.  </p></div>

与其他状态类似,单个工具类不会同时包含明暗两种样式 —— 你需要分别为明亮与深色模式选择不同类。

Generated CSS
.dark\:bg-gray-800 {  @media (prefers-color-scheme: dark) {    background-color: var(--color-gray-800);  }}

更多详情请参阅 dark mode 文档。

使用类组合

在 Tailwind 中,经常会组合多个类构造出单个 CSS 属性的值,例如为元素添加多重滤镜:

HTML
<div class="blur-sm grayscale">  <!-- ... --></div>

这些效果依赖于 CSS 的 filter 属性,Tailwind 利用 CSS 变量实现组合使用:

Generated CSS
.blur-sm {  --tw-blur: blur(var(--blur-sm));  filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-grayscale,);}.grayscale {  --tw-grayscale: grayscale(100%);  filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-grayscale,);}

上面的生成 CSS 略作简化,但关键是每个工具类只设置对应的 CSS 变量,然后 filter 属性组合所有变量(未设置的变量回退为空)。

这种方法同样用于 渐变效果阴影颜色变形 等。

使用任意值

Tailwind 中很多工具类基于 主题变量,如 bg-blue-500text-xlshadow-md,它们映射到你的配色、字号和阴影上。

当需要使用主题之外的特殊值时,可用方括号语法指定任意值:

HTML
<button class="bg-[#316ff6] ...">  Sign in with Facebook</button>

这对不在调色板中的颜色(如上例中的 Facebook 蓝)非常有用,还适用于构建特定网格布局等复杂场景:

HTML
<div class="grid grid-cols-[24rem_2.5rem_minmax(0,1fr)]">  <!-- ... --></div>

使用 calc() 等复杂值时也可以这样书写:

HTML
<div class="max-h-[calc(100dvh-(--spacing(6))]">  <!-- ... --></div>

甚至可以生成任意 CSS(例如设定 CSS 变量):

HTML
<div class="[--gutter-width:1rem] lg:[--gutter-width:2rem]">  <!-- ... --></div>

更多信息请参阅 using arbitrary values 文档。

这是如何实现的?

Tailwind CSS 并非一个静态样式表,它会根据你项目中实际使用的类名生成 CSS。

它会扫描项目所有文件,寻找所有类似类名的字符串:

Button.jsx
export default function Button({ size, children }) {  let sizeClasses = {    md: "px-4 py-2 rounded-md text-base",    lg: "px-5 py-3 rounded-lg text-lg",  }[size];  return (    <button type="button" className={`font-bold ${sizeClasses}`}>      {children}    </button>  );}

找到潜在类名后,Tailwind 为每个生成对应 CSS,并将所有样式编译到一个样式表内。

正因如此,即使类名中使用了任意值(如 bg-[#316ff6]),Tailwind 也能生成所需 CSS,即使该值并不属于主题。

更多内容请见 detecting classes in source files 文档。

复杂选择器

有时你需要基于多重条件为元素设定样式,例如在深色模式、特定断点、悬停状态以及带有特定 data 属性时:

HTML
<button class="dark:lg:data-current:hover:bg-indigo-600 ...">  <!-- ... --></button>
Simplified CSS
@media (prefers-color-scheme: dark) and (width >= 64rem) {  button[data-current]:hover {    background-color: var(--color-indigo-600);  }}

Tailwind 还支持 group-hover,可以在父元素悬停时改变子元素样式:

HTML
<a href="#" class="group rounded-lg p-8">  <!-- ... -->  <span class="group-hover:underline">Read more…</span></a>
Simplified CSS
@media (hover: hover) {  a:hover span {    text-decoration-line: underline;  }}

对于更复杂情况(比如样式化不可控的 HTML),Tailwind 支持 arbitrary variants,允许你在类名中直接书写任意选择器。

HTML
<div class="[&>[data-active]+span]:text-blue-600 ...">  <span data-active><!-- ... --></span>  <span>This text will be blue</span></div>
Simplified CSS
div > [data-active] + span {  color: var(--color-blue-600);}

何时使用内联样式

在 Tailwind 项目中,内联样式仍然十分有用,特别是当样式值来自数据库或 API 时:

branded-button.jsx
export function BrandedButton({ buttonColor, textColor, children }) {  return (    <button      style={{        backgroundColor: buttonColor,        color: textColor,      }}      className="rounded-md px-3 py-1.5 font-medium"    >      {children}    </button>  );}

另一种情况是,当任意值非常复杂难以阅读时,用内联样式会更直观:

HTML
<div class="grid-[2fr_max(0,var(--gutter-width))_calc(var(--gutter-width)+10px)]"><div style="grid-template-columns: 2fr max(0, var(--gutter-width)) calc(var(--gutter-width) + 10px)">  <!-- ... --></div>

另一种常见模式是通过内联样式设置 CSS 变量,然后利用工具类引用这些变量:

branded-button.jsx
export function BrandedButton({ buttonColor, buttonColorHover, textColor, children }) {  return (    <button      style={{        "--bg-color": buttonColor,        "--bg-color-hover": buttonColorHover,        "--text-color": textColor,      }}      className="bg-(--bg-color) text-(--text-color) hover:bg-(--bg-color-hover) ..."    >      {children}    </button>  );}

管理重复

使用纯工具类构建项目时,可能会遇到多处重复相同样式的情况。

例如,指南开头中,每个头像的工具类重复了五次:

Contributors

204
<div>  <div class="flex items-center space-x-2 text-base">    <h4 class="font-semibold text-slate-900">Contributors</h4>    <span class="bg-slate-100 px-2 py-1 text-xs font-semibold text-slate-700 ...">204</span>  </div>  <div class="mt-3 flex -space-x-2 overflow-hidden">    <img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="https://images.unsplash.com/photo-1491528323818-fdd1faba62cc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="" />    <img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="" />    <img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="https://images.unsplash.com/photo-1500648767791-00dcc994a43e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2.25&w=256&h=256&q=80" alt="" />    <img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="" />    <img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="https://images.unsplash.com/photo-1517365830460-955ce3ccd263?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="" />  </div>  <div class="mt-3 text-sm font-medium">    <a href="#" class="text-blue-500">+ 198 others</a>  </div></div>

其实不用担心,这个问题的解决策略与你日常处理重复代码的方式相同。

使用循环

通常,页面中重复出现的元素只需编写一次,通过循环动态渲染。

例如,上文重复出现的头像在真实项目中肯定是通过循环生成的:

Contributors

204
<div>  <div class="flex items-center space-x-2 text-base">    <h4 class="font-semibold text-slate-900">Contributors</h4>    <span class="bg-slate-100 px-2 py-1 text-xs font-semibold text-slate-700 ...">204</span>  </div>  <div class="mt-3 flex -space-x-2 overflow-hidden">    {#each contributors as user}      <img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src={user.avatarUrl} alt={user.handle} />    {/each}  </div>  <div class="mt-3 text-sm font-medium">    <a href="#" class="text-blue-500">+ 198 others</a>  </div></div>

使用多光标编辑

当重复代码集中在单个文件中的某处时,利用 多光标编辑 快速同时编辑多个类名通常是最简单的方法。

你会发现这种方式常常是最优解,如果能够同时快速编辑所有重复项,就没必要引入额外抽象。

<nav class="flex justify-center space-x-4">  <a href="/dashboard" class="font-medium rounded-lg px-3 py-2 text-gray-700 hover:bg-gray-100 hover:text-gray-900">    Home  </a>  <a href="/team" class="font-medium rounded-lg px-3 py-2 text-gray-700 hover:bg-gray-100 hover:text-gray-900">    Team  </a>  <a href="/projects" class="font-medium rounded-lg px-3 py-2 text-gray-700 hover:bg-gray-100 hover:text-gray-900">    Projects  </a>  <a href="/reports" class="font-medium rounded-lg px-3 py-2 text-gray-700 hover:bg-gray-100 hover:text-gray-900">    Reports  </a></nav>

使用组件

当你希望在多个文件中重用样式时,最佳策略是在使用 React、Svelte 或 Vue 等框架时创建组件,或在使用 Blade、ERB、Twig、Nunjucks 等模板语言时创建模板局部:

Beach
Private Villa
$299 USD per night
export function VacationCard({ img, imgAlt, eyebrow, title, pricing, url }) {  return (    <div>      <img className="rounded-lg" src={img} alt={imgAlt} />      <div className="mt-4">        <div className="text-xs font-bold text-sky-500">{eyebrow}</div>        <div className="mt-1 font-bold text-gray-700">          <a href={url} className="hover:underline">            {title}          </a>        </div>        <div className="mt-2 text-sm text-gray-600">{pricing}</div>      </div>    </div>  );}

现在你可以在任意位置使用该组件,同时样式的单一来源确保了它们可以在一个地方轻松更新。

使用自定义 CSS

如果你使用的是 ERB 或 Twig 等模板语言,而不是 React 或 Vue,创建模板局部来处理小组件可能显得有些繁琐,相比之下,使用简单的 CSS 类如 btn 更为直接。

虽然对于更复杂的组件,强烈建议创建模板局部以便样式和结构能在一个地方封装,但编写一些自定义 CSS 也是完全可以的。

以下是一个 btn-primary 类的示例,使用 主题变量 保持设计一致性:

HTML
<button class="btn-primary">Save changes</button>
CSS
@import "tailwindcss";@layer components {  .btn-primary {    border-radius: calc(infinity * 1px);    background-color: var(--color-violet-500);    padding-inline: --spacing(5);    padding-block: --spacing(2);    font-weight: var(--font-weight-semibold);    color: var(--color-white);    box-shadow: var(--shadow-md);    &:hover {      @media (hover: hover) {        background-color: var(--color-violet-700);      }    }  }}

不过,对于任何比单个 HTML 元素更复杂的情况,我们强烈建议使用模板局部,以便样式和结构能在一个地方封装。

版权所有 © 2025 Tailwind Labs Inc.·商标政策