TailwindCSS Flexbox 完整指南:flex、justify、align、gap 一次搞定 | TailwindCSS 完整教學
在 TailwindCSS 裡,Flexbox 是最常用、也最值得先練熟的一維版面引擎——只要對容器寫上
flex,再搭配justify-*決定主軸怎麼分配、items-*決定交軸怎麼對齊、gap-*拉開間距、flex-1讓子項等分空間,就能一組 utility 搞定置中、等分、換行這些每天都在寫的版面需求。這是 TailwindCSS 完整教學 系列的第九篇,我們會把整套 Flexbox 工具類從容器到子項一次講透,並以 v4 為預設、標註與 v3 的差異。
前言
Flexbox(彈性盒子,Flexible Box Layout) 是 CSS 專為「一維排列」設計的版面模型——所謂一維,指的是它一次只處理「一條軸線」上的排列,要嘛是一排橫的、要嘛是一列縱的。它解決的正是傳統 CSS 最頭痛的幾件事:垂直置中、等分空間、依內容自動伸縮、彈性換行。在 Flexbox 出現以前,這些需求得靠 float、table、負 margin 這類 hack 拼湊,既難寫又難維護;有了 Flexbox,一個 display: flex 加上幾個對齊屬性就能優雅解決。而 TailwindCSS 把整套 Flexbox 規格一對一包裝成好記、可組合的 utility class,你不必再手寫 justify-content: space-between,只要 justify-between 就好。
用一個現實世界的類比來理解:一個 flex 容器,就像一根可以自動伸縮、自動對齊的「彈性層架」。你把幾個東西(子項)放上這根層架,層架會幫你決定——它們該貼左、貼右、還是平均散開(這是主軸 justify-* 在管的事);它們在上下方向該對齊頂端、底端、還是置中(這是交軸 items-* 在管的事);東西之間要留多寬的縫(gap-*);哪個東西該撐大去吃掉多出來的空間、哪個該固定不動(flex-1、flex-none)。你甚至可以把層架轉個方向,讓東西改成由上往下疊(flex-col)。Tailwind 把這根「智慧層架」的每個旋鈕都做成一顆好記的 class,讓你像轉旋鈕一樣組合出想要的排列。
本篇你將學到:
- flex 容器與方向:
flex/inline-flex建立容器、flex-row/flex-col切換主軸方向、flex-wrap控制換行 - 主軸與交軸對齊:
justify-*(主軸分配)、items-*(交軸單行對齊)、content-*(交軸多行分配)、gap-*(子項間距) - 子項的伸縮控制:
flex-grow/shrink/basis三個原子屬性,以及flex-1/flex-auto/flex-none/flex-initial四個常用簡寫 - 個別子項微調:
order-*調整視覺順序、self-*(align-self)讓單一子項覆蓋容器的交軸對齊
本系列以 TailwindCSS v4 為預設版本,本篇會明確標註每一項與 v3 的差異。
核心概念
Flexbox 工具類全景:容器 vs 子項
學 Flexbox 最重要的第一步,是分清楚「哪些 class 寫在容器上、哪些寫在子項上」。這是最多初學者卡關的地方——把該給子項的 flex-1 寫到容器上,或把該給容器的 justify-center 寫到子項上,效果就完全不對。下面這張表把兩類工具並列,先建立全景地圖:
| 作用對象 | CSS 屬性 | 代表工具類 | 用途 |
|---|---|---|---|
| 容器 | display | flex、inline-flex | 宣告這是 flex 容器 |
| 容器 | flex-direction | flex-row、flex-col、flex-row-reverse | 決定主軸方向 |
| 容器 | flex-wrap | flex-wrap、flex-nowrap、flex-wrap-reverse | 子項是否換行 |
| 容器 | justify-content | justify-start、justify-center、justify-between | 主軸方向的對齊與分配 |
| 容器 | align-items | items-start、items-center、items-stretch | 交軸方向的單行對齊 |
| 容器 | align-content | content-center、content-between | 交軸方向的多行分配(需換行) |
| 容器 | gap | gap-4、gap-x-4、gap-y-2 | 子項之間的間距 |
| 子項 | flex(簡寫) | flex-1、flex-auto、flex-none | grow/shrink/basis 三合一 |
| 子項 | flex-grow | grow、grow-0 | 是否吃掉剩餘空間 |
| 子項 | flex-shrink | shrink、shrink-0 | 是否允許被壓縮 |
| 子項 | flex-basis | basis-0、basis-1/2、basis-64 | 子項的基礎大小 |
| 子項 | order | order-first、order-1、order-last | 視覺排列順序 |
| 子項 | align-self | self-start、self-center、self-end | 覆蓋容器對這一項的交軸對齊 |
這張表最需要先建立的認知只有一句話:justify-*、items-*、gap-*、flex-*方向 這些是「容器的旋鈕」,寫在 flex 容器上;flex-1、grow、basis-*、order-*、self-* 這些是「子項的旋鈕」,寫在容器的直接子元素上。 記住這個分界,你就已經避開了 Flexbox 一半的錯誤。
主軸與交軸:Flexbox 的心臟
要真正搞懂 justify-* 與 items-*,必須先理解 Flexbox 的兩條軸:主軸(main axis) 與 交軸(cross axis)。主軸是「子項排列的方向」,交軸則是與它垂直的另一個方向。關鍵在於:這兩條軸會隨 flex-direction 翻轉。
flex-row(預設):主軸 = 水平 flex-col:主軸 = 垂直
────────────────────────── ──────────────────────────
主軸 → ┌──────────┐ ← 交軸(水平)
┌──┐ ┌──┐ ┌──┐ │ A │
│A │ │B │ │C │ └──────────┘
└──┘ └──┘ └──┘ ┌──────────┐
↑ 交軸(垂直) │ B │ 主軸 ↓
└──────────┘
justify-between(沿主軸分配) items-center(沿交軸對齊)
────────────────────────── ──────────────────────────
┌─┐ ┌─┐ ┌─┐ ┌────────────────────────┐
│A│ │B│ │C│ │ ┌──┐ ┌────┐ ┌──┐ │
└─┘ └─┘ └─┘ │ │A │ │ B │ │C │ │
主軸方向平均散開 │ └──┘ └────┘ └──┘ │
└────────────────────────┘
交軸方向(高度)置中對齊
有了這張圖,兩組對齊工具的分工就清楚了。justify-*(對應 justify-content)控制主軸方向:justify-start/justify-end/justify-center 讓子項貼主軸的起點、終點或置中;justify-between 讓首尾子項貼邊、其餘均分間隙;justify-around 讓每個子項左右各有等量間距;justify-evenly 則讓所有間隙(含頭尾)完全相等。而 items-*(對應 align-items)控制交軸方向的單行對齊:items-start/items-end/items-center 對齊交軸的起點、終點或置中;items-stretch(預設值)讓子項在交軸方向撐滿容器高度;items-baseline 則讓子項的文字基線對齊。
這也解釋了為什麼「水平垂直完美置中」的黃金公式是 flex items-center justify-center——在預設的 flex-row 下,justify-center 管水平置中、items-center 管垂直置中,兩者一起就是正中央。
順帶標註一個 v4 差異:justify-* 系列在 v4 補上了 justify-normal 與 justify-stretch,對應 CSS 較新的規格值;gap-* 在 v3 就已支援 Flexbox(早年 Flexbox 沒有 gap,要靠 margin 硬湊,這段歷史包袱已成過去),v4 沿用並更完善。整體而言 Flexbox 這組工具的「命名」在 v3 到 v4 之間相當穩定,遷移時幾乎不需要改動,這也是 Flexbox 值得先練熟的原因之一。
align-content:只有換行時才登場
還有一個容易和 items-* 混淆的工具:content-*(對應 align-content)。它們的差別是「單行 vs 多行」——items-* 控制單行內子項在交軸的對齊,content-* 控制多行之間在交軸的分配。所以 content-* 只有在容器 flex-wrap 換行、且產生了多行時才有作用;如果容器只有一行,寫 content-* 完全無效。想像一個換行後排成三列的標籤雲,content-between 會把這三列在垂直方向上下撐開分配,而 items-center 則是管每一列「內部」的對齊——兩者管的層級不同。
子項的伸縮:grow / shrink / basis 與四個簡寫
容器決定了大方向,但每個子項要「吃多少空間」則由三個子項屬性決定:flex-grow(有剩餘空間時要不要放大)、flex-shrink(空間不夠時要不要縮小)、flex-basis(在放大縮小之前的基礎大小)。這三者組合起來就是 CSS 的 flex 簡寫。Tailwind 幫最常見的四種組合取了好記的名字:
| 簡寫 class | 等同 CSS flex | grow / shrink / basis | 白話解釋 |
|---|---|---|---|
flex-1 | 1 1 0% | 放大 / 縮小 / 0 | 忽略內容大小,純比例等分空間(最常用) |
flex-auto | 1 1 auto | 放大 / 縮小 / auto | 以內容為基準,再按比例分配剩餘空間 |
flex-initial | 0 1 auto | 不放大 / 縮小 / auto | 預設值,可縮不可長 |
flex-none | 0 0 auto | 不放大 / 不縮小 / auto | 固定尺寸,完全不伸縮 |
若不想用簡寫、要單獨微調,也有原子工具可用:grow/grow-0 控制放大、shrink/shrink-0 控制縮小、basis-* 設定基礎大小(basis-0、basis-1/2、basis-64、basis-[320px] 皆可)。實務上最高頻的兩招是:要幾個欄位等寬平分,全部給 flex-1;要某個元素固定尺寸不被壓縮(如側邊欄、圖示),給 flex-none 或 shrink-0。
這裡值得再釐清一個常見疑問:flex-basis 和直接寫 width 有什麼差別?當方向是 flex-row 時,兩者看起來很像,但語義不同。basis-* 表達的是「這個 flex 子項的初始大小」,它會作為 grow/shrink 計算的起點,語義上更貼合 Flexbox 的運作模型;width 則是「最終寬度」的概念。建議在 flex 子項上優先用 basis-*,讓「初始大小 → 依剩餘空間伸縮」的意圖更清楚;只有在需要硬性鎖死尺寸(通常搭配 flex-none)時才改用 w-*。另外提醒:flex-basis 只沿主軸生效——flex-row 時它控制寬度、flex-col 時它控制高度,這也是 Flexbox「一切以主軸為準」的一致設計。
order 與 align-self:個別子項的微調
最後兩個子項工具用於「例外處理」。order-* 改變子項的視覺排列順序而不動 HTML 結構——order-first(排到最前)、order-last(排到最後)、order-1 到 order-12 指定數值順序,數字小的排前面。這在響應式設計裡很有用,例如手機版想把某個區塊提前顯示、桌面版又放回原位,只要在斷點前綴切換 order-* 即可,不必重寫 HTML。不過要提醒一個無障礙細節:order 只改變視覺順序,不改變 DOM 順序與鍵盤 Tab 的走訪順序,所以請避免用它做出「視覺與閱讀順序嚴重脫節」的版面,以免螢幕閱讀器使用者困惑。
self-*(對應 align-self)則讓單一子項覆蓋容器設定的 items-* 交軸對齊——容器是 items-center,但你想讓其中某一項貼底,就在那一項寫 self-end;self-auto 則回歸容器設定、self-stretch 讓它在交軸撐滿。這兩個都是「大方向由容器定、少數例外由子項自己調」的精修工具,讓你不必為了一個例外就拆散整個容器的對齊規則。
實作範例
理論看完,我們用幾個可執行的範例把工具串起來。以下都是完整的 HTML + Tailwind,可直接貼進頁面觀察效果。
範例一:完美置中與行內圖示按鈕
Flexbox 最經典的用途就是置中。過去讓一個區塊在畫面正中央是出了名的難,現在只要容器加 flex items-center justify-center 就好:
<!-- 讓卡片在整個視口垂直+水平正中央 -->
<div class="flex items-center justify-center min-h-screen bg-gray-50">
<div class="bg-white rounded-xl shadow-lg p-8 max-w-md w-full">
<h2 class="text-2xl font-bold text-gray-900 text-center mb-6">登入</h2>
<!-- 表單內容 -->
</div>
</div>
<!-- 行內置中:讓圖示與文字在按鈕裡垂直對齊、並用 gap 拉開 -->
<button class="inline-flex items-center gap-2 px-4 py-2 bg-cyan-600 text-white rounded-lg">
<svg class="w-4 h-4"><!-- 圖示 --></svg>
<span>傳送訊息</span>
</button>
這裡有兩個重點。第一,容器的 flex items-center justify-center 就是黃金置中公式——justify-center 管主軸(水平)置中、items-center 管交軸(垂直)置中,搭配 min-h-screen 撐滿視口高度,卡片就穩穩落在正中央。第二,按鈕用的是 inline-flex 而非 flex:flex 是塊級容器會獨佔一行,inline-flex 則讓按鈕維持行內特性、可以和其他文字並排,同時內部仍享有 flex 的對齊能力——這正是「圖示+文字」按鈕的標準寫法,items-center 確保圖示與文字垂直對齊、gap-2 拉開它們的間距。
範例二:導覽列佈局(justify-between + flex-1)
第二個高頻場景是導覽列——Logo 靠左、CTA 靠右、選單置中。這是 justify-between 與 flex-1 搭配的經典舞台:
<!-- 標準導覽列:Logo 左、選單中、按鈕右 -->
<header class="flex items-center justify-between px-6 py-4 border-b border-gray-200">
<!-- 左側:Logo -->
<a href="/" class="flex items-center gap-3 shrink-0">
<img src="/logo.svg" alt="Logo" class="h-8 w-8">
<span class="text-xl font-bold text-gray-900">BenzHub</span>
</a>
<!-- 中間:主選單,flex-1 讓它吃掉中間空間、內部再置中 -->
<nav class="hidden md:flex flex-1 items-center justify-center gap-8">
<a href="/about" class="text-sm font-medium text-gray-600 hover:text-cyan-600">關於</a>
<a href="/product" class="text-sm font-medium text-gray-600 hover:text-cyan-600">產品</a>
<a href="/blog" class="text-sm font-medium text-gray-600 hover:text-cyan-600">文章</a>
</nav>
<!-- 右側:CTA 按鈕 -->
<div class="flex items-center gap-3 shrink-0">
<a href="/login" class="text-sm font-medium text-gray-600">登入</a>
<a href="/signup" class="px-4 py-2 bg-cyan-600 text-white text-sm font-medium rounded-lg">
免費試用
</a>
</div>
</header>
這個範例展示了三種對齊工具協同運作。最外層 header 用 justify-between 把左、中、右三塊沿主軸推開;items-center 讓它們在垂直方向對齊。中間的 nav 加了 flex-1,讓它吃掉左右兩塊之外的所有剩餘空間,再靠內部的 justify-center 把選單項目置中——這是「彈性中欄」的標準做法。兩側的 Logo 與按鈕群組則加了 shrink-0,避免視窗變窄時被壓縮變形。留意 nav 上的 hidden md:flex——它結合了上一篇學過的響應式顯示:手機隱藏、md 以上才顯示並成為 flex 容器。
範例三:響應式卡片列與方向切換
第三個範例示範 flex-wrap 換行與 flex-col md:flex-row 響應式方向切換,這是卡片列與版面重排的核心:
<!-- 響應式卡片列:手機單欄、平板雙欄、桌面三欄,超出自動換行 -->
<div class="flex flex-wrap gap-6">
<div class="basis-full sm:basis-[calc(50%-12px)] lg:basis-[calc(33.333%-16px)]
bg-white rounded-xl border border-gray-200 p-6">
<h3 class="font-semibold text-gray-900">卡片標題</h3>
<p class="text-gray-600 text-sm mt-2">卡片描述文字,數量不定時 flex-wrap 會自動換行。</p>
</div>
<!-- 更多卡片,重複相同結構 -->
</div>
<!-- 響應式方向:手機直向堆疊、桌面橫向並排 -->
<div class="flex flex-col md:flex-row gap-4">
<aside class="md:w-64 shrink-0 bg-gray-50 rounded-lg p-4">側邊欄</aside>
<main class="flex-1 min-w-0 bg-white rounded-lg p-4">主內容區(flex-1 吃掉剩餘空間)</main>
</div>
上半段的卡片列用 flex flex-wrap gap-6:flex-wrap 讓子項在一行放不下時自動換到下一行,gap-6 同時處理水平與垂直間距(換行後上下也有一致間隔,這正是 gap 勝過 margin 的地方)。每張卡片用 basis-* 設定基礎寬度,並用響應式前綴在不同斷點切換一欄、兩欄、三欄的寬度。下半段則展示 flex-col md:flex-row 這個極常用的響應式招式——手機上 flex-col 讓側欄與主內容垂直堆疊,到 md 斷點以上切成 flex-row 水平並排。主內容區的 flex-1 min-w-0 是重點:flex-1 讓它吃掉側欄以外的空間,而 min-w-0 是防止內部長文字撐爆容器的必備搭配(詳見下一節的坑)。
範例四:Sticky Footer 與平均分配空間
最後兩個實用版型:讓頁腳永遠貼在視口底部的 Sticky Footer,以及讓子項平均分配空間的等分排列:
<!-- Sticky Footer:flex-col + flex-1 把 footer 推到底部 -->
<div class="flex flex-col min-h-screen">
<header class="flex items-center px-6 py-4 border-b border-gray-200">頁頭</header>
<!-- flex-1 讓 main 撐滿所有剩餘高度,把 footer 頂到最底 -->
<main class="flex-1 px-6 py-8">頁面主內容(內容再少,footer 也不會浮上來)</main>
<footer class="px-6 py-4 border-t border-gray-200 text-sm text-gray-500">
© 2026 BenzHub
</footer>
</div>
<!-- 平均分配:三個子項用 flex-1 等寬平分 -->
<div class="flex gap-4">
<div class="flex-1 bg-cyan-100 rounded-lg p-4 text-center">項目 A</div>
<div class="flex-1 bg-cyan-100 rounded-lg p-4 text-center">項目 B</div>
<div class="flex-1 bg-cyan-100 rounded-lg p-4 text-center">項目 C</div>
</div>
<!-- 固定+彈性:側欄固定寬、主內容吃剩餘 -->
<div class="flex items-stretch gap-4">
<aside class="flex-none w-64 bg-gray-50 rounded-lg p-4">側邊欄(固定 256px)</aside>
<main class="flex-1 bg-white rounded-lg p-4">主內容(佔滿剩餘空間)</main>
</div>
Sticky Footer 的訣竅是外層 flex flex-col min-h-screen(垂直排列、至少一個視口高),再讓中間的 main 加 flex-1——它會撐滿 header 與 footer 之外的所有垂直空間,把 footer 自然頂到底部,就算頁面內容很少也不會出現「頁腳浮在畫面中間」的尷尬。下方的等分排列展示 flex-1 的另一種威力:三個子項都寫 flex-1,它們就會忽略各自內容大小、完全等寬平分容器。最後的「固定+彈性」組合則是 flex-none(側欄固定 256px)搭配 flex-1(主內容吃剩餘)的黃金拍檔,配上 items-stretch 讓兩者等高——這是後台版面最常見的骨架。
常見錯誤與最佳實踐
四個最容易踩的 Flexbox 坑
坑一:flex-1 的子項裝了長文字,卻撐爆容器(缺 min-w-0)。 這是 Flexbox 最惡名昭彰的隱性陷阱。flex 子項的 min-width 預設是 auto(由內容決定),所以即使你寫了 flex-1,一段不換行的長文字或程式碼仍會把子項撐超過應有的寬度、溢出容器。解法是在該子項補上 min-w-0:
<div class="flex gap-4">
<div class="flex-1">
<p class="truncate">超長不換行的文字...</p> <!-- ❌ 沒 min-w-0,文字撐爆版面 -->
</div>
</div>
<div class="flex gap-4">
<div class="flex-1 min-w-0">
<p class="truncate">超長不換行的文字...</p> <!-- ✅ 加了 min-w-0,truncate 才生效 -->
</div>
</div>
坑二:用 margin 製造間距,最後一個子項多出邊距。 給每個子項加 mr-4 會讓最後一項也多出右邊距、破壞對齊,還得寫 last:mr-0 補救;換行時 margin 更難兼顧上下間距。正解是容器用 gap-*:
<div class="flex">
<div class="mr-4">A</div> <!-- ❌ 最後一個也有 mr-4,且換行時上下不對 -->
<div class="mr-4">B</div>
<div>C</div>
</div>
<div class="flex gap-4"> <!-- ✅ 只在子項之間產生間距,頭尾乾淨、換行也對齊 -->
<div>A</div>
<div>B</div>
<div>C</div>
</div>
坑三:只有單行卻用 content-*,以為能垂直分配。 content-*(align-content)只在容器有多行(flex-wrap 換行後)時才作用;單行容器要對齊交軸請用 items-*:
<div class="flex content-center h-40">...</div> <!-- ❌ 單行時 content-center 無效 -->
<div class="flex items-center h-40">...</div> <!-- ✅ 單行交軸置中要用 items-center -->
<div class="flex flex-wrap content-center h-40">...</div> <!-- ✅ 換行後 content-center 才有意義 -->
坑四:對 flex 子項用 float,或以為 justify-* 能對齊子項自己。 flex 容器內的子項套 float 完全無效(Flexbox 會忽略它);另外 justify-* 是容器管「子項在主軸如何分配」,不是子項自己的對齊工具——想單獨移動某一個子項在主軸的位置,改用 ml-auto(把它推到最右)之類的 auto margin 技巧:
<div class="flex">
<a href="/">Logo</a>
<a href="/login" class="ml-auto">登入</a> <!-- ✅ ml-auto 把單一項推到主軸最末 -->
</div>
Flexbox 最佳實踐清單
- 先分清容器與子項工具:
justify-*/items-*/gap-*寫容器,flex-1/grow/self-*寫子項——這是避開一半錯誤的關鍵。 - 置中就用
flex items-center justify-center:一維置中最穩的黃金公式,別再用 margin 或 absolute 硬喬。 - 間距一律用
gap-*,不要用 margin:頭尾乾淨、換行也對齊,語義更清楚。 - 等分用
flex-1、固定不縮用flex-none/shrink-0:記住這兩招就能應付八成的空間分配需求。 flex-1子項若含長文字,補min-w-0:這是 truncate 與長內容不溢出的必要搭配。- 響應式重排用
flex-col md:flex-row:手機直向、桌面橫向,一行搞定版面重組。 - 一維用 Flexbox、二維用 Grid:只需要一排或一列時選 Flexbox;同時要控制行與列時,交給下一篇的 Grid。
小結
這是 TailwindCSS 完整教學 系列的第九篇。上一篇《Layout 與 Display》我們把 display 這個版面地基講透——用 block/flex/grid/hidden 決定元素的渲染模式、用 overflow 處理溢出、用 object-fit 填充圖片,其中就提到 flex 是「宣告一個彈性容器」的 display 模式。這一篇則深入 flex 這個最常用的一維版面引擎,把整套從容器到子項的工具一次講清楚。回顧幾個重點:
- 容器 vs 子項是第一分界:
justify-*/items-*/content-*/gap-*/flex-*方向寫在容器上,flex-1/grow/shrink/basis-*/order-*/self-*寫在子項上。 - 主軸與交軸會隨方向翻轉:
justify-*管主軸、items-*管交軸,主軸跟著flex-row/flex-col走;置中黃金公式是flex items-center justify-center。 - 子項伸縮看四個簡寫:
flex-1(等分)、flex-auto(依內容比例)、flex-initial(預設可縮不長)、flex-none(固定不伸縮),底層是 grow/shrink/basis 三個原子屬性。 - 間距與微調:
gap-*取代 margin 製造間距,order-*調視覺順序、self-*讓單一子項覆蓋交軸對齊。 - 最容易踩的坑:
flex-1長文字要配min-w-0、間距別用 margin、content-*只在換行時有效、flex 子項的float無效。
Flexbox 是一維排列的利器,但當你需要「同時控制行與列」的二維版面——像是相簿網格、儀表板、複雜的頁面骨架——它就顯得力不從心。下一篇 《TailwindCSS Grid 完整指南》,我們會進入二維版面的世界,把 grid-cols-*、grid-rows-*、col-span-*、gap-* 這些工具一次講透,看 Tailwind 如何用一組 utility 就搭出過去得寫一大段 CSS 才能完成的網格版面,並釐清 Flexbox 與 Grid 各自最適合的場景。