Core concepts
// title 不翻译 export const title = "Styling with utility classes"; export const description = "从受限的原子工具集中构建复杂组件。";
你可以通过在标记中直接组合多个单用途展示类 (utility classes) 来使用 Tailwind 进行样式设置:
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>例如,在上述用户界面中我们使用了:
flex、shrink-0 和 p-6)来控制整体布局max-w-sm 和 mx-auto)来限制卡片宽度并使其水平居中bg-white、rounded-xl 和 shadow-lg)来设定卡片外观size-12)来设置徽标图片的宽度和高度gap-x-4)来处理徽标和文本之间的间隔text-xl、text-black、font-medium 等)来为卡片文本设定样式这种样式设计方式虽然与许多传统最佳实践相悖,但一旦尝试你会立刻注意到以下几个非常重要的好处:
这些好处在小型项目中就十分明显,对于长期、大规模团队项目更是意义重大。
很多人最初会疑问,“这不就是内联样式吗?”在某种程度上确实如此 —— 你直接在元素上应用样式,而非先定义类名再通过类名设定样式。
不过,使用工具类相比内联样式具有很多优势,例如:
该组件完全响应式,包含一个具 hover 和 active 样式的按钮,并且全由工具类构建:

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:
.hover\:bg-sky-700 { &:hover { background-color: var(--color-sky-700); }}注意,该类仅在元素被悬停时生效,其唯一作用就是提供悬停样式。
这与传统 CSS 写法不同 —— 传统中一个类通常涵盖多个状态的样式:
<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 状态类似,你可以在工具类前添加断点前缀,为不同屏幕尺寸设定样式:
调整窗口大小查看布局变化
<div class="grid grid-cols-2 sm:grid-cols-3"> <!-- ... --></div>上例中,sm: 前缀确保 grid-cols-3 仅在 sm 断点及以上生效(默认 40rem)。
.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>与其他状态类似,单个工具类不会同时包含明暗两种样式 —— 你需要分别为明亮与深色模式选择不同类。
.dark\:bg-gray-800 { @media (prefers-color-scheme: dark) { background-color: var(--color-gray-800); }}更多详情请参阅 dark mode 文档。
在 Tailwind 中,经常会组合多个类构造出单个 CSS 属性的值,例如为元素添加多重滤镜:
<div class="blur-sm grayscale"> <!-- ... --></div>这些效果依赖于 CSS 的 filter 属性,Tailwind 利用 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-500、text-xl 和 shadow-md,它们映射到你的配色、字号和阴影上。
当需要使用主题之外的特殊值时,可用方括号语法指定任意值:
<button class="bg-[#316ff6] ..."> Sign in with Facebook</button>这对不在调色板中的颜色(如上例中的 Facebook 蓝)非常有用,还适用于构建特定网格布局等复杂场景:
<div class="grid grid-cols-[24rem_2.5rem_minmax(0,1fr)]"> <!-- ... --></div>使用 calc() 等复杂值时也可以这样书写:
<div class="max-h-[calc(100dvh-(--spacing(6))]"> <!-- ... --></div>甚至可以生成任意 CSS(例如设定 CSS 变量):
<div class="[--gutter-width:1rem] lg:[--gutter-width:2rem]"> <!-- ... --></div>更多信息请参阅 using arbitrary values 文档。
Tailwind CSS 并非一个静态样式表,它会根据你项目中实际使用的类名生成 CSS。
它会扫描项目所有文件,寻找所有类似类名的字符串:
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 属性时:
<button class="dark:lg:data-current:hover:bg-indigo-600 ..."> <!-- ... --></button>@media (prefers-color-scheme: dark) and (width >= 64rem) { button[data-current]:hover { background-color: var(--color-indigo-600); }}Tailwind 还支持 group-hover,可以在父元素悬停时改变子元素样式:
<a href="#" class="group rounded-lg p-8"> <!-- ... --> <span class="group-hover:underline">Read more…</span></a>@media (hover: hover) { a:hover span { text-decoration-line: underline; }}对于更复杂情况(比如样式化不可控的 HTML),Tailwind 支持 arbitrary variants,允许你在类名中直接书写任意选择器。
<div class="[&>[data-active]+span]:text-blue-600 ..."> <span data-active><!-- ... --></span> <span>This text will be blue</span></div>div > [data-active] + span { color: var(--color-blue-600);}在 Tailwind 项目中,内联样式仍然十分有用,特别是当样式值来自数据库或 API 时:
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> );}另一种情况是,当任意值非常复杂难以阅读时,用内联样式会更直观:
<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 变量,然后利用工具类引用这些变量:
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> );}使用纯工具类构建项目时,可能会遇到多处重复相同样式的情况。
例如,指南开头中,每个头像的工具类重复了五次:
<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>其实不用担心,这个问题的解决策略与你日常处理重复代码的方式相同。
通常,页面中重复出现的元素只需编写一次,通过循环动态渲染。
例如,上文重复出现的头像在真实项目中肯定是通过循环生成的:
<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 等模板语言时创建模板局部:
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> );}现在你可以在任意位置使用该组件,同时样式的单一来源确保了它们可以在一个地方轻松更新。
如果你使用的是 ERB 或 Twig 等模板语言,而不是 React 或 Vue,创建模板局部来处理小组件可能显得有些繁琐,相比之下,使用简单的 CSS 类如 btn 更为直接。
虽然对于更复杂的组件,强烈建议创建模板局部以便样式和结构能在一个地方封装,但编写一些自定义 CSS 也是完全可以的。
以下是一个 btn-primary 类的示例,使用 主题变量 保持设计一致性:
<button class="btn-primary">Save changes</button>@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 元素更复杂的情况,我们强烈建议使用模板局部,以便样式和结构能在一个地方封装。