核心概念
使用 Tailwind 的工具类构建复杂组件。
您可以通过在标记中直接组合许多单一用途的表现类(工具类)来使用 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 className="text-xl font-medium text-black dark:text-white">ChitChat</div> <p className="text-gray-500 dark:text-gray-400">您有一条新消息!</p> </div></div>
例如,在上面的 UI 中我们使用了:
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
等)来设置卡片文本的样式这种样式设计方式与许多传统最佳实践相矛盾,但一旦您尝试,您会很快注意到一些非常重要的好处:
这些好处在小项目上产生很大的差异,但对于在大规模长期项目上工作的团队来说,它们更有价值。
对这种方法的常见反应是想知道,"这不就是内联样式吗?"在某些方面确实如此——您直接将样式应用于元素,而不是为它们分配类名然后设置该类的样式。
但是使用工具类比内联样式有许多重要优势,例如:
这个组件是完全响应式的,包含一个带有悬停和激活样式的按钮,完全用工具类构建:
Erin Lindford
产品工程师
<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">产品工程师</p> </div> <button class="border-purple-200 text-purple-600 hover:border-transparent hover:bg-purple-600 hover:text-white active:bg-purple-700 ..."> 发消息 </button> </div></div>
要为悬停或焦点等状态的元素设置样式,请在任何工具类前加上您想要针对的状态前缀,例如 hover:bg-sky-700
:
悬停在此按钮上查看背景颜色变化
<button class="bg-sky-500 hover:bg-sky-700 ...">保存更改</button>
这些前缀在 Tailwind 中称为变体,它们只在该变体的条件匹配时应用工具类的样式。
以下是 hover:bg-sky-700
类生成的 CSS:
.hover\:bg-sky-700 { &:hover { background-color: var(--color-sky-700); }}
注意这个类只有在元素被悬停时才会起作用?它的唯一作用是提供悬停样式——没有其他。
这与您编写传统 CSS 的方式不同,在传统 CSS 中,单个类通常会为许多状态提供样式:
<button class="btn">保存更改</button><style> .btn { background-color: var(--color-sky-500); &:hover { background-color: var(--color-sky-700); } }</style>
当您使用工具类构建整个项目时,您最终会发现自己重复某些模式以在不同地方重新创建相同的样式。
例如,这里每个头像图像的工具类重复了五次:
<div> <div class="flex items-center space-x-2 text-base"> <h4 class="font-semibold text-slate-900">贡献者</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">贡献者</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">保存更改</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 元素更复杂的事情,我们强烈建议使用模板部分,以便样式和结构可以封装在一个地方。
当您向元素添加两个目标相同 CSS 属性的类时,后一个类在样式表中获胜。因此,在下面的示例中,元素将接收 display: grid
,即使 flex
最后出现在实际 class
属性中:
<div class="grid flex"> <!-- ... --></div>
.flex { display: flex;}.grid { display: grid;}
一般来说,您应该只向元素添加一个您实际想要的类——不要添加两个冲突的类:
export function Example({ gridLayout }) { return <div className={gridLayout ? "grid" : "flex"}>{/* ... */}</div>;}
使用组件库(如 React 或 Vue)时,这意味着暴露特定属性以用于样式自定义,而不是让消费者添加额外类,因为这些样式将经常冲突。
当您真的需要强制特定工具类生效并且没有其他方法来管理特定性时,您可以在类名末尾添加 !
以使所有声明 !important
:
<div class="bg-teal-500 bg-red-500!"> <!-- ... --></div>
.bg-red-500\! { background-color: var(--color-red-500) !important;}.bg-teal-500 { background-color: var(--color-teal-500);}
如果您正在向具有现有复杂 CSS 和高特定性规则的项目添加 Tailwind,您可以使用 important
标志在导入 Tailwind 时标记 所有 工具类为 !important
:
@import "tailwindcss" important;
@layer utilities { .flex { display: flex !important; } .gap-4 { gap: 1rem !important; } .underline { text-decoration-line: underline !important; }}
如果您项目的类名与 Tailwind CSS 工具类冲突,您可以使用 Tailwind 生成的类和 CSS 变量前缀所有 Tailwind 工具类,使用 prefix
选项:
@import "tailwindcss" prefix(tw);
@layer theme { :root { --tw-color-red-500: oklch(0.637 0.237 25.331); }}@layer utilities { .tw\:text-red-500 { color: var(--tw-color-red-500); }}