核心概念(Core Concepts)
使用一組受限的原始通用類別建構複雜的元件。
在 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>舉例來說,在上面的 UI 中我們使用了:
flex、shrink-0 和 p-6)來控制整體佈局max-w-sm 和 mx-auto)來限制卡片寬度並使其水平置中bg-white、rounded-xl 和 shadow-lg)來設定卡片的外觀樣式size-12)來設定 logo 圖片的寬度和高度gap-x-4)來處理 logo 和文字之間的間距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 或 focus 等狀態下設定元素的樣式,請在任何通用類別前加上你想要針對的狀態前綴,例如 hover:bg-sky-700:
將滑鼠移到這個按鈕上,看看背景顏色的變化
<button class="bg-sky-500 hover:bg-sky-700 ...">Save changes</button>這些前綴在 Tailwind 中稱為變體,它們只在該變體的條件符合時才會套用通用類別的樣式。
以下是 hover:bg-sky-700 類別產生的 CSS:
.hover\:bg-sky-700 { &:hover { background-color: var(--color-sky-700); }}注意這個類別在元素沒有被 hover 時不會做任何事嗎?它的_唯一_工作就是提供 hover 樣式 — 沒有其他的。
這與傳統 CSS 的寫法不同,在傳統 CSS 中,單一類別通常會為多種狀態提供樣式:
<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>在 hover、focus 和其他狀態的文件中了解更多。
就像 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)); }}在響應式設計文件中了解更多。
在深色模式下設定元素的樣式,只需要在任何你想要在深色模式啟用時套用的通用類別前加上 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>就像 hover 狀態或媒體查詢一樣,重要的是要理解單一通用類別永遠不會同時包含淺色和深色樣式 — 你是透過使用多個類別來設定深色模式的樣式,一個用於淺色模式樣式,另一個用於深色模式樣式。
.dark\:bg-gray-800 { @media (prefers-color-scheme: dark) { background-color: var(--color-gray-800); }}在深色模式文件中了解更多。
在 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 對漸層、陰影顏色、變形等也使用相同的方法。
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() 等 CSS 功能時也很有用,即使你使用的是主題值:
<div class="max-h-[calc(100dvh-(--spacing(6)))]"> <!-- ... --></div>甚至有一個語法可以產生完全任意的 CSS,包括任意的屬性名稱,這對於設定 CSS 變數很有用:
<div class="[--gutter-width:1rem] lg:[--gutter-width:2rem]"> <!-- ... --></div>在使用任意值的文件中了解更多。
Tailwind CSS 不像你可能習慣的其他 CSS 框架那樣是一個大型靜態樣式表 — 它會根據你編譯 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,並將它們全部編譯成一個只包含你實際需要的樣式的樣式表。
由於 CSS 是根據類別名稱產生的,Tailwind 可以識別使用任意值的類別(如 bg-[#316ff6])並產生必要的 CSS,即使該值不是主題的一部分。
在偵測原始檔中的類別中了解更多關於這是如何運作的。
有時你需要在多個條件的組合下設定元素的樣式,例如在深色模式、特定中斷點、hover 時,以及元素具有特定 data 屬性時。
以下是在 Tailwind 中的範例:
<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 這樣的功能,讓你可以在特定父元素被 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; }}這個 group-* 語法也適用於其他變體,例如 group-focus、group-active 和更多。
對於非常複雜的情境_(特別是當你要設定你無法控制的 HTML 時)_,Tailwind 支援任意變體,讓你可以直接在類別名稱中寫任何你想要的選擇器:
<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 CSS 專案中仍然非常有用,特別是當值來自動態來源(如資料庫或 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 元素更複雜的任何東西,我們強烈建議使用模板片段,這樣樣式和結構可以封裝在一個地方。
當你添加兩個針對相同 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 這樣基於元件的函式庫時,這通常意味著為樣式自訂公開特定的 props,而不是讓使用者從元件外部添加額外的類別,因為那些樣式經常會衝突。
當你真的需要強制讓特定的通用類別生效,而且沒有其他方法管理優先權時,你可以在類別名稱末尾添加 ! 來使所有宣告都變成 !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);}如果你要將 Tailwind 添加到一個已經有複雜 CSS 和高優先權規則的專案中,你可以在匯入 Tailwind 時使用 important 旗標來將_所有_通用類別標記為 !important:
@import "tailwindcss" important;@layer utilities { .flex { display: flex !important; } .gap-4 { gap: 1rem !important; } .underline { text-decoration-line: underline !important; }}如果你的專案有與 Tailwind CSS 通用類別衝突的類別名稱,你可以使用 prefix 選項為所有 Tailwind 產生的類別和 CSS 變數添加前綴:
@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); }}