1. 核心概念
  2. 使用实用工具类进行样式设计

核心概念

使用实用工具类进行样式设计

从一组受限的原始实用工具构建复杂的组件。

概述

您可以使用 Tailwind 通过直接在标记中组合许多单用途的演示类(实用工具类)来设置样式

聊天室

您有一条新消息!

<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>

例如,在上面的 UI 中,我们使用了

以这种方式设置样式与许多传统的最佳实践相矛盾,但是一旦您尝试过,您会很快注意到一些非常重要的好处

  • 您可以更快地完成工作 — 您无需花费任何时间来想出类名、决定选择器或在 HTML 和 CSS 文件之间切换,因此您的设计可以很快地组合在一起。
  • 进行更改感觉更安全 — 向元素添加或删除实用工具类只会影响该元素,因此您不必担心意外破坏使用相同 CSS 的另一个页面。
  • 维护旧项目更容易 — 更改内容只需在项目中找到该元素并更改类,而不是试图记住您六个月没有碰过的所有自定义 CSS 的工作原理。
  • 您的代码更易于移植 — 由于结构和样式都位于同一位置,您可以轻松地复制和粘贴整个 UI 块,即使在不同的项目之间也是如此。
  • 您的 CSS 停止增长 — 由于实用工具类具有很高的可重用性,因此您的 CSS 不会随着您添加到项目的每个新功能而线性增长。

这些好处在小型项目中会产生很大的影响,但对于在大型长期项目上工作的团队来说,它们更有价值。

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

对此方法的常见反应是想知道,“这不就是内联样式吗?” 在某些方面,确实如此 — 您是将样式直接应用于元素,而不是为它们分配类名,然后设置该类的样式。

但是,使用实用工具类比内联样式有很多重要的优点,例如

  • 使用约束进行设计 — 使用内联样式,每个值都是一个幻数。 使用实用工具,您可以从预定义的样式系统中选择样式,这使得构建视觉一致的 UI 更加容易。
  • 悬停、焦点和其他状态 — 内联样式无法定位悬停或焦点等状态,但 Tailwind 的状态变体可以轻松使用实用工具类来设置这些状态的样式。
  • 媒体查询 — 您不能在内联样式中使用媒体查询,但是可以使用 Tailwind 的响应式变体来轻松构建完全响应式的界面。

此组件完全响应,并包含带有悬停和活动样式的按钮,并且完全使用实用工具类构建

Woman's Face

艾琳·林德福德

产品工程师

<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 中称为变体,并且它们仅在匹配该变体的条件时才应用实用工具类中的样式。

这是为 hover:bg-sky-700 类生成的 CSS

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

请注意,除非元素悬停,否则此类不执行任何操作? 它的唯一工作是提供悬停样式 — 没有其他内容。

这与您编写传统 CSS 的方式不同,在传统 CSS 中,单个类通常会为许多状态提供样式

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

您甚至可以在 Tailwind 中堆叠变体,以在多个条件匹配时应用实用工具,例如组合 hover:disabled:

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

在文档中了解更多关于在悬停、焦点和其他状态上设置元素样式的信息。

媒体查询和断点

就像悬停和焦点状态一样,您可以通过在任何实用工具的前面加上您要应用该样式的断点来设置元素在不同断点处的样式

调整此示例的大小以查看布局变化

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

在上面的示例中,sm: 前缀确保 grid-cols-3 仅在 sm 断点及以上触发,默认值为 40rem

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

响应式设计文档中了解更多信息。

定位深色模式

在暗黑模式下为元素设置样式,只需在任何你想在暗黑模式激活时应用的实用工具类前面添加 dark: 前缀即可。

亮色模式

倒着写

零重力笔可以在任何方向书写,包括倒着写。它甚至可以在外太空工作。

深色模式

倒着写

零重力笔可以在任何方向书写,包括倒着写。它甚至可以在外太空工作。

<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>

就像悬停状态或媒体查询一样,需要理解的重要一点是,单个实用工具类永远不会包含亮色和暗黑两种样式——你通过使用多个类来为暗黑模式设置样式,一个用于亮色模式样式,另一个用于暗黑模式样式。

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

暗黑模式文档中了解更多信息。

使用类组合

在 Tailwind 中,很多时候你甚至会使用多个类来构建单个 CSS 属性的值,例如向元素添加多个滤镜。

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

这两个效果都依赖于 CSS 中的 filter 属性,因此 Tailwind 使用 CSS 变量来实现将这些效果组合在一起。

生成的 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 对渐变阴影颜色变换等也使用了相同的方法。

使用任意值

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>

即使你正在使用主题值,当需要使用 CSS 功能(如 calc())时,它也很有用。

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

甚至有一种用于生成完全任意的 CSS(包括任意属性名称)的语法,这对于设置 CSS 变量非常有用。

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

使用任意值的文档中了解更多信息。

这是如何工作的?

Tailwind CSS 不是像你可能习惯的其他 CSS 框架那样的一个大型静态样式表,它会根据你在编译 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,并将所有内容编译成一个仅包含你实际需要的样式的样式表。

由于 CSS 是根据类名生成的,因此 Tailwind 可以识别使用任意值的类,例如 bg-[#316ff6] 并生成必要的 CSS,即使该值不是主题的一部分。

在源文件中检测类中了解更多关于其工作原理的信息。

复杂选择器

有时你需要根据多种条件的组合来设置元素的样式,例如在暗黑模式下、在特定的断点处、悬停时以及当元素具有特定的数据属性时。

这是一个使用 Tailwind 的示例,如下所示:

HTML
<button class="dark:lg:data-current:hover:bg-indigo-600 ...">  <!-- ... --></button>
简化的 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>
简化的 CSS
@media (hover: hover) {  a:hover span {    text-decoration-line: underline;  }}

group-* 语法也适用于其他变体,例如 group-focusgroup-active更多

对于非常复杂的场景(尤其是在为你不控制的 HTML 设置样式时),Tailwind 支持任意变体,它可以让你直接在类名中编写任何你想要的选择器。

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

何时使用内联样式

在 Tailwind CSS 项目中,内联样式仍然非常有用,尤其是在值来自数据库或 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>  );}

管理重复

当你仅使用实用工具类构建整个项目时,你不可避免地会发现自己在不同的位置重复某些模式以重新创建相同的设计。

例如,此处每个头像图像的实用工具类重复了五次。

贡献者

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>

别慌!实际上,这并不是你可能担心的那种问题,而处理它的策略是你每天都在做的事情。

使用循环

很多时候,在渲染页面中多次出现的设计元素实际上只被编写一次,因为实际的标记是在循环中渲染的。

例如,本指南开头的重复头像几乎肯定会在实际项目中以循环方式呈现。

贡献者

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
私人别墅
每晚 299 美元
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 之类的东西,那么与像 btn 这样的简单 CSS 类相比,为像按钮这样小的东西创建模板局部可能会让人觉得有点过头。

虽然强烈建议你为更复杂的组件创建适当的模板局部,但当模板局部显得笨重时,编写一些自定义 CSS 完全没问题。

以下是 btn-primary 类可能的样子,使用主题变量来保持设计一致。

HTML
<button class="btn-primary">Save changes</button>  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.·商标政策