TailwindCSS Flexbox 完整指南:flex、justify、align、gap 一次搞定 | TailwindCSS 完整教學

2026/08/09
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 出現以前,這些需求得靠 floattable、負 margin 這類 hack 拼湊,既難寫又難維護;有了 Flexbox,一個 display: flex 加上幾個對齊屬性就能優雅解決。而 TailwindCSS 把整套 Flexbox 規格一對一包裝成好記、可組合的 utility class,你不必再手寫 justify-content: space-between,只要 justify-between 就好。

用一個現實世界的類比來理解:一個 flex 容器,就像一根可以自動伸縮、自動對齊的「彈性層架」。你把幾個東西(子項)放上這根層架,層架會幫你決定——它們該貼左、貼右、還是平均散開(這是主軸 justify-* 在管的事);它們在上下方向該對齊頂端、底端、還是置中(這是交軸 items-* 在管的事);東西之間要留多寬的縫(gap-*);哪個東西該撐大去吃掉多出來的空間、哪個該固定不動(flex-1flex-none)。你甚至可以把層架轉個方向,讓東西改成由上往下疊(flex-col)。Tailwind 把這根「智慧層架」的每個旋鈕都做成一顆好記的 class,讓你像轉旋鈕一樣組合出想要的排列。

本篇你將學到:

  • flex 容器與方向flexinline-flex 建立容器、flex-rowflex-col 切換主軸方向、flex-wrap 控制換行
  • 主軸與交軸對齊justify-*(主軸分配)、items-*(交軸單行對齊)、content-*(交軸多行分配)、gap-*(子項間距)
  • 子項的伸縮控制flex-growshrinkbasis 三個原子屬性,以及 flex-1flex-autoflex-noneflex-initial 四個常用簡寫
  • 個別子項微調order-* 調整視覺順序、self-*(align-self)讓單一子項覆蓋容器的交軸對齊

本系列以 TailwindCSS v4 為預設版本,本篇會明確標註每一項與 v3 的差異。

核心概念

Flexbox 工具類全景:容器 vs 子項

學 Flexbox 最重要的第一步,是分清楚「哪些 class 寫在容器上、哪些寫在子項上」。這是最多初學者卡關的地方——把該給子項的 flex-1 寫到容器上,或把該給容器的 justify-center 寫到子項上,效果就完全不對。下面這張表把兩類工具並列,先建立全景地圖:

作用對象CSS 屬性代表工具類用途
容器displayflexinline-flex宣告這是 flex 容器
容器flex-directionflex-rowflex-colflex-row-reverse決定主軸方向
容器flex-wrapflex-wrapflex-nowrapflex-wrap-reverse子項是否換行
容器justify-contentjustify-startjustify-centerjustify-between主軸方向的對齊與分配
容器align-itemsitems-startitems-centeritems-stretch交軸方向的單行對齊
容器align-contentcontent-centercontent-between交軸方向的多行分配(需換行)
容器gapgap-4gap-x-4gap-y-2子項之間的間距
子項flex(簡寫)flex-1flex-autoflex-nonegrow/shrink/basis 三合一
子項flex-growgrowgrow-0是否吃掉剩餘空間
子項flex-shrinkshrinkshrink-0是否允許被壓縮
子項flex-basisbasis-0basis-1/2basis-64子項的基礎大小
子項orderorder-firstorder-1order-last視覺排列順序
子項align-selfself-startself-centerself-end覆蓋容器對這一項的交軸對齊

這張表最需要先建立的認知只有一句話:justify-*items-*gap-*flex-*方向 這些是「容器的旋鈕」,寫在 flex 容器上;flex-1growbasis-*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-startjustify-endjustify-center 讓子項貼主軸的起點、終點或置中;justify-between 讓首尾子項貼邊、其餘均分間隙;justify-around 讓每個子項左右各有等量間距;justify-evenly 則讓所有間隙(含頭尾)完全相等。而 items-*(對應 align-items)控制交軸方向的單行對齊:items-startitems-enditems-center 對齊交軸的起點、終點或置中;items-stretch(預設值)讓子項在交軸方向撐滿容器高度;items-baseline 則讓子項的文字基線對齊。

這也解釋了為什麼「水平垂直完美置中」的黃金公式是 flex items-center justify-center——在預設的 flex-row 下,justify-center 管水平置中、items-center 管垂直置中,兩者一起就是正中央。

順帶標註一個 v4 差異:justify-* 系列在 v4 補上了 justify-normaljustify-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 flexgrow / shrink / basis白話解釋
flex-11 1 0%放大 / 縮小 / 0忽略內容大小,純比例等分空間(最常用)
flex-auto1 1 auto放大 / 縮小 / auto以內容為基準,再按比例分配剩餘空間
flex-initial0 1 auto不放大 / 縮小 / auto預設值,可縮不可長
flex-none0 0 auto不放大 / 不縮小 / auto固定尺寸,完全不伸縮

若不想用簡寫、要單獨微調,也有原子工具可用:growgrow-0 控制放大、shrinkshrink-0 控制縮小、basis-* 設定基礎大小(basis-0basis-1/2basis-64basis-[320px] 皆可)。實務上最高頻的兩招是:要幾個欄位等寬平分,全部給 flex-1;要某個元素固定尺寸不被壓縮(如側邊欄、圖示),給 flex-noneshrink-0

這裡值得再釐清一個常見疑問:flex-basis 和直接寫 width 有什麼差別?當方向是 flex-row 時,兩者看起來很像,但語義不同。basis-* 表達的是「這個 flex 子項的初始大小」,它會作為 growshrink 計算的起點,語義上更貼合 Flexbox 的運作模型;width 則是「最終寬度」的概念。建議在 flex 子項上優先用 basis-*,讓「初始大小 → 依剩餘空間伸縮」的意圖更清楚;只有在需要硬性鎖死尺寸(通常搭配 flex-none)時才改用 w-*。另外提醒:flex-basis 只沿主軸生效——flex-row 時它控制寬度、flex-col 時它控制高度,這也是 Flexbox「一切以主軸為準」的一致設計。

order 與 align-self:個別子項的微調

最後兩個子項工具用於「例外處理」。order-* 改變子項的視覺排列順序而不動 HTML 結構——order-first(排到最前)、order-last(排到最後)、order-1order-12 指定數值順序,數字小的排前面。這在響應式設計裡很有用,例如手機版想把某個區塊提前顯示、桌面版又放回原位,只要在斷點前綴切換 order-* 即可,不必重寫 HTML。不過要提醒一個無障礙細節:order 只改變視覺順序,不改變 DOM 順序與鍵盤 Tab 的走訪順序,所以請避免用它做出「視覺與閱讀順序嚴重脫節」的版面,以免螢幕閱讀器使用者困惑。

self-*(對應 align-self)則讓單一子項覆蓋容器設定的 items-* 交軸對齊——容器是 items-center,但你想讓其中某一項貼底,就在那一項寫 self-endself-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 而非 flexflex 是塊級容器會獨佔一行,inline-flex 則讓按鈕維持行內特性、可以和其他文字並排,同時內部仍享有 flex 的對齊能力——這正是「圖示+文字」按鈕的標準寫法,items-center 確保圖示與文字垂直對齊、gap-2 拉開它們的間距。

範例二:導覽列佈局(justify-between + flex-1)

第二個高頻場景是導覽列——Logo 靠左、CTA 靠右、選單置中。這是 justify-betweenflex-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>

這個範例展示了三種對齊工具協同運作。最外層 headerjustify-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-6flex-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: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(垂直排列、至少一個視口高),再讓中間的 mainflex-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-1growself-* 寫子項——這是避開一半錯誤的關鍵。
  • 置中就用 flex items-center justify-center:一維置中最穩的黃金公式,別再用 margin 或 absolute 硬喬。
  • 間距一律用 gap-*,不要用 margin:頭尾乾淨、換行也對齊,語義更清楚。
  • 等分用 flex-1、固定不縮用 flex-noneshrink-0:記住這兩招就能應付八成的空間分配需求。
  • flex-1 子項若含長文字,補 min-w-0:這是 truncate 與長內容不溢出的必要搭配。
  • 響應式重排用 flex-col md:flex-row:手機直向、桌面橫向,一行搞定版面重組。
  • 一維用 Flexbox、二維用 Grid:只需要一排或一列時選 Flexbox;同時要控制行與列時,交給下一篇的 Grid。

小結

這是 TailwindCSS 完整教學 系列的第九篇。上一篇《Layout 與 Display》我們把 display 這個版面地基講透——用 blockflexgridhidden 決定元素的渲染模式、用 overflow 處理溢出、用 object-fit 填充圖片,其中就提到 flex 是「宣告一個彈性容器」的 display 模式。這一篇則深入 flex 這個最常用的一維版面引擎,把整套從容器到子項的工具一次講清楚。回顧幾個重點:

  • 容器 vs 子項是第一分界justify-*items-*content-*gap-*flex-*方向 寫在容器上,flex-1growshrinkbasis-*order-*self-* 寫在子項上。
  • 主軸與交軸會隨方向翻轉justify-* 管主軸、items-* 管交軸,主軸跟著 flex-rowflex-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 各自最適合的場景。

BenZ Software Developer

熱愛技術的軟體開發者,在這裡分享程式開發經驗與學習筆記。

本週主打

AI 自動化入門包

你每天手動在做的那些煩事,其實 AI 可以自己跑。這份給你 10 個照著做就會的自動化工作流 + 50 個複製即用的提示詞,不用會寫程式。

看看這個產品 →