TailwindCSS 間距系統:padding、margin、space、gap 完整指南 | TailwindCSS 完整教學

2026/08/12
TailwindCSS 間距系統:padding、margin、space、gap 完整指南 | TailwindCSS 完整教學

TailwindCSS 裡,間距系統(Spacing) 是決定版面「呼吸感」的靈魂——元素內部要留多少 padding、彼此之間要隔多遠 margin、一排子項要用什麼方式拉開,全靠這套工具。只要用 p-*px-*py-* 控制內距、m-*mx-auto 控制外距與置中、space-x-*space-y-*gap-* 控制子元素間隔,就能把一個「擠成一團」的版面調成「疏密有致」。這是 TailwindCSS 完整教學 系列的第十二篇,我們會把 paddingmarginspacegap 一次講透,並帶你理解 v4 由單一 --spacing 變數動態推導間距刻度的設計,以 v4 為預設、標註與 v3 的差異。

前言

間距(Spacing) 指的是元素「內部空間」與「外部空間」的控制——前者是 CSS 的 padding(內距,內容到邊框的距離),後者是 margin(外距,邊框到相鄰元素的距離)。上一篇 《定位系統》 我們學會了怎麼把元素精準釘在畫面任意位置、疊在正確的層級上;但一個賞心悅目的介面,光有「位置」還不夠,元素與元素之間、內容與邊框之間,都需要恰到好處的留白。間距拿捏得好,版面就從「能看」進化到「耐看」;拿捏不好,再漂亮的配色與字體也會顯得侷促雜亂。間距系統就是這門「留白的藝術」的工具箱。

用一個現實世界的類比來理解 padding 與 margin 的差別:想像一幅裱框的畫。 畫作本身是「內容(content)」,畫框內側到畫作之間那圈白色卡紙就是 padding——它把內容從邊框往內推、留出內部的呼吸空間;而這幅裱好的畫掛上牆後,它和旁邊那幅畫之間的牆面距離,就是 margin——決定畫與畫之間隔多遠。padding 屬於元素「自己內部」的事、會被背景色包住;margin 是元素「對外」的事、是透明的、不含背景。搞懂這個「內卡紙 vs 畫間距」的分野,你就抓住了間距系統一半的精髓。

TailwindCSS 的妙處在於,它不讓你隨手亂填 13px27px 這種零散數字,而是提供一套一致的間距刻度(spacing scale):以 0.25rem(4px)為基準單位,p-1 是 4px、p-2 是 8px、p-4 是 16px……整個網站的留白都落在這套刻度上,視覺節奏自然統一。到了 v4,這套刻度更進化成由「單一變數動態推導」,讓刻度既一致又能無限延伸。

本篇你將學到:

  • padding 內距p-*(四邊)、px-*py-*(水平/垂直軸)、pt-*pr-*pb-*pl-*(單邊)、以及 v4 的邏輯屬性 ps-*pe-*
  • margin 外距m-* 家族、mx-auto 水平置中招式、ml-automt-auto 推擠技巧、以及負值 -mt-4
  • 子元素間距space-x-*space-y-* 的運作機制、與 gap-* 的關鍵差異、該用哪一個
  • v4 間距刻度:單一 --spacing 變數如何以 calc(var(--spacing) * n) 推導所有刻度,讓 p-13 這種任意倍數開箱即用,以及任意值 p-[18px] 寫法

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

核心概念

間距工具類的分類地圖

間距系統的工具乍看很多,但其實高度規律。抓住兩條軸線就能秒懂:一是「控制的是內距(p)還是外距(m)」,二是「作用在哪個方向(全部/水平軸/垂直軸/單邊)」。下面這張表是整篇文章的地圖:

方向padding(內距)margin(外距)對應 CSS
四邊p-*m-*padding / margin
水平(左右)px-*mx-*padding-inline / margin-inline
垂直(上下)py-*my-*padding-block / margin-block
pt-*mt-*padding-top / margin-top
pr-*mr-*padding-right / margin-right
pb-*mb-*padding-bottom / margin-bottom
pl-*ml-*padding-left / margin-left
邏輯起始ps-*ms-*padding-inline-start / margin-inline-start
邏輯結束pe-*me-*padding-inline-end / margin-inline-end

規律非常清楚:字首 p 管 padding、m 管 margin;第二個字母決定方向——x 是水平軸、y 是垂直軸、t/r/b/l 是上右下左四個單邊、s/e 是邏輯上的起始/結束(logical start/end,RTL 友善)。記住這套命名法,你就能反推出任何一顆間距 class,不必死背。而 space-*gap-* 則是另一類——它們不作用在「單一元素自己」,而是控制「一群子元素彼此之間」的間隔,稍後專章討論。

v4 的核心:單一 --spacing 變數推導整套刻度

Tailwind 的間距數字(p-44m-88)不是像素,而是刻度值。基準單位是 0.25rem(在預設 16px 根字級下等於 4px),所有數字刻度都是這個基準的倍數:

Tailwind 值計算rempx常見用途
000px重置間距
px1px精細 1px 微調
11 × 0.25rem0.25rem4px緊密元素間距
22 × 0.25rem0.5rem8px圖示內距
33 × 0.25rem0.75rem12px緊湊 UI
44 × 0.25rem1rem16px標準基礎間距
66 × 0.25rem1.5rem24px卡片 padding
88 × 0.25rem2rem32px區塊間距
1212 × 0.25rem3rem48pxsection 內距
1616 × 0.25rem4rem64px大型 section 間距
2424 × 0.25rem6rem96px英雄區間距

這裡就是 v4 最重要的變化。在 v3 時代,上表是一張「硬編碼的靜態對照表」——表上有的數字才存在,p-13p-15 這種表上沒有的值,預設一律不成立,要嘛用任意值、要嘛去 config 擴充。v4 徹底翻新:它把每個數字刻度定義成一條公式——

/* v4:每個數字刻度都由這條公式動態推導 */
/* padding: calc(var(--spacing) * <n>) */
/* 預設 --spacing 為 0.25rem,所以: */
/* p-4  → calc(0.25rem * 4)  = 1rem   (16px) */
/* p-13 → calc(0.25rem * 13) = 3.25rem (52px)  ← 不必擴充,直接成立! */

換句話說,在 v4 裡任意正整數(甚至小數)倍數都開箱即用p-13m-15gap-25pt-17 全部有效,因為它們只是把 13152517 代進公式而已。這在過去是不可能的,你會得到「class 不存在」的結果。

更妙的是「單一基準」帶來的一致性:不只 p-*m-*,連 gap-*w-*h-*inset-*translate-*scroll-m-* 等所有走數字刻度的 utility,統統共用這同一個 --spacing 變數。所以只要在 @theme 裡覆寫一次基準,整套間距與尺寸系統就會等比縮放:

@import "tailwindcss";

@theme {
  --spacing: 0.2rem;   /* 把基準從 0.25rem 縮成 0.2rem,全站數字刻度一次縮緊 */
}

改這一行,p-4m-8gap-6w-64 全都同步變小——這種「牽一髮動全身」的可控性,正是 v4 間距系統的設計哲學。

v4 差異標註:v3 的間距刻度是靜態對照表,表外的值不存在;v4 改為由單一 --spacing 變數以 calc() 動態推導,任意倍數(如 p-13)皆成立,且 p-*m-*gap-*w-* 等共用同一基準,覆寫 --spacing 即可等比縮放整套系統。

space 與 gap:控制「子元素之間」的兩種思路

前面的 p-*m-* 都是作用在「元素自己」。但實務上更常見的需求是:一整排/一整列子元素,彼此之間要有均等的間隔。 Tailwind 提供兩種工具,思路完全不同:

工具機制作用位置適用場景
gap-* / gap-x-* / gap-y-*CSS 原生 gap 屬性容器層級,統一在子項「之間」開縫Flexbox、Grid(首選
space-x-* / space-y-*在第 2 個起的子項加 margin子元素層級(相鄰選擇器)非 flex/grid 的單純堆疊清單

兩者的差別用一張示意圖最清楚:

gap-4(容器統一開縫,只在「之間」,換行也自動套用)
┌──────┐ ←4→ ┌──────┐ ←4→ ┌──────┐
│  A   │     │  B   │     │  C   │      ← 首尾外緣無多餘間距
└──────┘     └──────┘     └──────┘         換行時列與列之間也自動有 gap

space-x-4(在第 2 個起的子項加 margin-left 模擬間距)
┌──────┐    ┌──────┐    ┌──────┐
│  A   │    │  B   │    │  C   │
└──────┘    └──────┘    └──────┘
  第一個     ←加 ml-4    ←加 ml-4       ← 不理解換行,換到第二列間距會亂
  無 margin

結論是:只要容器是 flexgrid,一律優先用 gap-* 它是 CSS 的原生機制,由容器統一負責、只在子項「之間」開縫、首尾不會多出間距,而且 flex-wrap 換行時,列與列之間也會自動套用縱向間距——這正是格狀排版最想要的行為。space-x-*space-y-* 則是 Tailwind 用「相鄰選擇器」在第二個以後的子項加 margin 來模擬間距,它不理解換行、換到第二列時間距會亂掉,只適合保留給「不能/不想把容器變成 flex 或 grid」的單純垂直堆疊清單。

v4 差異標註:v3 的 space-x-*space-y-* 是用 > * + * 選擇器搭配偽元素方案實作;v4 改為直接在子項計算 margin,行為更可預測、也更容易和其他 margin 共存。無論版本,都不要在同一個容器同時寫 gap-*space-*——兩者會疊加,間距變成非預期的兩倍。

實作範例

理論看完,我們用幾個高頻的可執行範例把工具串起來。以下都是完整的 HTML + Tailwind,可直接貼進頁面觀察效果。

範例一:mx-auto 水平置中容器

最經典的間距招式,就是用 mx-automargin-left: auto; margin-right: auto)把一個有最大寬度的區塊在頁面水平置中——這是幾乎每個網站主內容容器的標準寫法:

<!-- 標準內容容器:限制最大寬度 + 水平置中 + 響應式左右內距 -->
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
  <h1 class="text-3xl font-bold text-gray-900">頁面標題</h1>
  <p class="mt-4 text-gray-600">這段內容永遠置中,兩側留有隨螢幕變化的內距。</p>
</div>

這裡三顆 class 各司其職。max-w-4xl 限制容器最大寬度(避免在寬螢幕上文字拉得太長)、mx-auto 讓左右外距自動均分把容器推到中央、px-4 sm:px-6 lg:px-8 則給左右內距,並用響應式前綴讓手機留白小、桌面留白大。要特別注意:mx-auto 要生效,元素必須有明確的寬度限制(如這裡的 max-w-4xl),否則區塊會撐滿整行、左右沒有多餘空間可分配,看起來就不會置中。另外 mt-4 示範了單邊外距——標題與段落之間拉開 1rem 的縱向呼吸。

範例二:卡片的 padding 與內部節奏

卡片是 padding 的主場——用 p-* 把內容從邊框往內推、留出內部呼吸空間,再用 margin 或 space 控制內部元素的縱向節奏:

<!-- 卡片:外層 padding 決定內部留白,內部用間距建立節奏 -->
<div class="max-w-sm p-6 bg-white rounded-2xl shadow-sm border border-gray-100">
  <span class="inline-block px-3 py-1 bg-cyan-50 text-cyan-700 text-xs font-semibold rounded-full">
    教學
  </span>
  <h3 class="mt-4 text-lg font-bold text-gray-900">TailwindCSS 間距系統</h3>
  <p class="mt-2 text-sm text-gray-600 leading-relaxed">
    用一致的 spacing scale,讓版面從「能看」進化到「耐看」。
  </p>
  <button class="mt-6 w-full py-2.5 bg-cyan-600 text-white text-sm font-medium rounded-lg hover:bg-cyan-700">
    開始閱讀
  </button>
</div>

這個範例展示了 padding 的兩種尺度。外層卡片的 p-61.5rem)是「容器級」內距,決定整張卡片內容離邊框多遠;而徽章的 px-3 py-1 則是「元件級」內距——水平 0.75rem、垂直 0.25rem,讓小標籤的文字四周有剛好的留白。內部元素之間則靠遞增的單邊上外距建立節奏:mt-4(標題)、mt-2(描述,較近表示關聯緊密)、mt-6(按鈕,較遠表示是獨立動作)。用 padding 管內部留白、用 margin 管元素間距,各司其職,版面就會條理分明。

範例三:space-y 堆疊清單 vs gap 格狀排版

這個範例並列兩種子元素間距工具,讓你直接感受它們各自的舞台:

<!-- space-y-*:適用於非 flex/grid 的單純垂直堆疊清單 -->
<ul class="space-y-3">
  <li class="p-4 bg-white rounded-lg border border-gray-200">清單項目 1</li>
  <li class="p-4 bg-white rounded-lg border border-gray-200">清單項目 2</li>
  <li class="p-4 bg-white rounded-lg border border-gray-200">清單項目 3</li>
</ul>

<!-- gap-*:Flexbox/Grid 的首選,換行時列與列也自動有間距 -->
<div class="mt-8 grid grid-cols-2 sm:grid-cols-3 gap-4">
  <div class="p-4 bg-white rounded-lg border border-gray-200">格子 A</div>
  <div class="p-4 bg-white rounded-lg border border-gray-200">格子 B</div>
  <div class="p-4 bg-white rounded-lg border border-gray-200">格子 C</div>
  <div class="p-4 bg-white rounded-lg border border-gray-200">格子 D</div>
</div>

上半的 <ul> 是一個普通的區塊容器(不是 flex/grid),用 space-y-3 在相鄰項目之間加 0.75rem 的縱向間距——這是 space-* 的正當用途:單純的垂直堆疊、不需要換行邏輯。下半的 grid ... gap-4 才是主流做法:grid-cols-2 sm:grid-cols-3 切出格狀骨架,gap-4 統一控制格子之間的橫向與縱向間距,當格子換到下一列時,列與列之間也自動有 1rem 縫隙——這種「換行自動保持間距」的能力是 space-* 給不了的。記住原則:格狀/彈性排版用 gap,純堆疊清單才考慮 space

範例四:ml-auto 推擠與負 margin 頭像堆疊

margin 還有兩個進階招式:用 auto 在 flex 容器中「推擠」元素,以及用「負值」製造重疊效果。

<!-- ml-auto 把右側元素推到最右端 -->
<div class="flex items-center px-4 py-3 bg-white border-b border-gray-200">
  <span class="text-lg font-bold text-gray-900">Logo</span>
  <nav class="ml-auto flex gap-6 text-sm text-gray-600">   <!-- ml-auto 吃掉左側所有剩餘空間 -->
    <a href="#" class="hover:text-gray-900">首頁</a>
    <a href="#" class="hover:text-gray-900">關於</a>
  </nav>
</div>

<!-- 負值 space:讓頭像互相重疊,做出堆疊效果 -->
<div class="mt-6 flex items-center">
  <div class="flex -space-x-3">   <!-- 負間距讓每個頭像向左偏移,製造重疊 -->
    <img src="/avatar1.jpg" alt="用戶1" class="w-10 h-10 rounded-full border-2 border-white object-cover">
    <img src="/avatar2.jpg" alt="用戶2" class="w-10 h-10 rounded-full border-2 border-white object-cover">
    <img src="/avatar3.jpg" alt="用戶3" class="w-10 h-10 rounded-full border-2 border-white object-cover">
    <div class="w-10 h-10 rounded-full border-2 border-white bg-gray-100 flex items-center justify-center text-xs font-medium text-gray-600">
      +9
    </div>
  </div>
  <span class="ml-4 text-sm text-gray-600">12 位成員</span>
</div>

上半展示 ml-auto 推擠:在 flex 容器裡,auto 外距會「吃掉」該方向所有剩餘空間,於是 nav 被推到最右端——這比手動算寬度或用定位乾淨太多,是做導覽列、工具列右側元素對齊的招牌手法(同理 mt-auto 可在 flex-col 容器把元素推到底部)。下半展示 負值間距-space-x-3 讓每個頭像向左偏移 0.75rem,做出社群產品常見的頭像重疊堆疊;末尾的 border-2 border-white 白邊讓重疊的頭像界線分明。負值就是「往反方向拉」,是製造重疊、突破容器邊界(breakout)等效果的利器。

範例五:邏輯屬性 ps-/pe- 與任意值

最後補上兩個進階寫法:v4 完整支援的邏輯屬性,以及跳脫刻度的任意值。

<!-- ps-/pe-:邏輯內距,在 RTL 語言自動翻轉方向 -->
<div class="relative">
  <svg class="absolute inset-y-0 left-3 my-auto w-5 h-5 text-gray-400"><!-- 搜尋圖示 --></svg>
  <!-- ps-10 給圖示留位、pe-4 給右側留白;RTL 時會自動左右對調 -->
  <input type="search" placeholder="搜尋..."
         class="w-full ps-10 pe-4 py-2 border border-gray-300 rounded-lg">
</div>

<!-- 任意值:刻度不夠精準時,直接指定確切數值 -->
<div class="p-[18px]">內距剛好 18px</div>
<div class="mt-[72px]">上外距固定 72px(如避開固定頁首)</div>
<div class="-mx-[1.5rem]">負任意值:突破容器左右邊界的全出血效果</div>

上半的 ps-10 pe-4v4 的邏輯屬性——ps-* 對應 padding-inline-start(邏輯起始側)、pe-* 對應 padding-inline-end(邏輯結束側)。在中文、英文這種左到右(LTR)的語言中,ps- 等同 pl-pe- 等同 pr-;但在阿拉伯文等右到左(RTL)語言中會自動翻轉。若網站要支援多語系,優先用 ps-pe-ms-me-,比寫死方向的 pl-pr- 省下大量 RTL 重構成本。下半展示任意值:當一致刻度剛好沒有你要的數字、或需求本身就是某個固定像素(例如避開一個 72px 高的固定頁首),用方括號 p-[18px]mt-[72px] 就能指定確切值,負任意值 -mx-[1.5rem] 則常用來做「全出血」——不過任意值屬於「逃生艙」,能用刻度就盡量用刻度,才能維持全站的視覺節奏。

常見錯誤與最佳實踐

四個最容易踩的間距坑

坑一:垂直 margin 的「邊距折疊(margin collapsing)」。 在正常文件流的垂直方向上,相鄰區塊元素的 margin-bottommargin-top 不會相加,而是折疊成「較大的那一個」。上元素 mb-4(16px)、下元素 mt-8(32px),最終間距是 32px 而非 48px。這常讓人誤以為間距工具壞了,其實是 CSS 原生行為。根治法:把父容器設成 flex flex-col 再用 gap-*——Flexbox/Grid 的子元素之間不會折疊,gap 設多少就是多少。

<!-- ❌ 靠各自的 margin 堆間距,會發生邊距折疊,間距不如預期 -->
<div>
  <p class="mb-4">段落 A</p>
  <p class="mt-8">段落 B</p>   <!-- 實際間距只有 32px,不是 48px -->
</div>

<!-- ✅ 改用 flex-col + gap,不折疊、完全可預測 -->
<div class="flex flex-col gap-8">
  <p>段落 A</p>
  <p>段落 B</p>   <!-- 穩定的 32px -->
</div>

坑二:在同一容器同時用 gap-*space-* 兩者機制不同卻都會產生間距,寫在一起會疊加,導致間距變成非預期的兩倍。同一容器請二選一,且在 flex/grid 中一律優先 gap

<!-- ❌ gap 和 space 疊加,間距變兩倍 -->
<div class="flex gap-4 space-x-4">...</div>

<!-- ✅ flex/grid 只用 gap -->
<div class="flex gap-4">...</div>

坑三:用 margin 代替 padding 處理「背景色內部的留白」。 margin 是透明的、在元素邊框之外,不會被背景色包住;padding 在邊框之內、會被背景色包含。想讓帶背景色的區塊內容四周有留白,必須用 padding,用 margin 只會把整塊往外推、內容仍緊貼邊緣。

<!-- ❌ 背景色不會包含 mt-4 的空間,內容仍緊貼上緣 -->
<div class="bg-cyan-100 mt-4">內容</div>

<!-- ✅ padding 在背景色之內,內容四周有留白 -->
<div class="bg-cyan-100 p-4">內容</div>

坑四:mx-auto 沒有寬度限制卻期待置中。 mx-auto 靠「把剩餘水平空間均分給左右外距」來置中,若元素本身撐滿整行(如區塊元素預設 width: auto),就沒有剩餘空間可分配,置中不會發生。務必搭配 max-w-*(或明確 w-*)給元素一個比容器窄的寬度。

間距系統最佳實踐清單

  • 內距用 padding、間距用 margin/gap:背景色內的留白一律 p-*,元素之間的距離用 m-* 或(在 flex/grid 中)gap-*
  • flex/grid 一律用 gap-*:比 space-* 更可預測、支援換行、首尾不多間距,是子元素間距的首選。
  • space-* 只留給純堆疊清單:非 flex/grid 的單純垂直列表才用 space-y-*,且切勿與 gap 混用。
  • 多用刻度、少用任意值p-4p-6 這類刻度值能維持全站節奏;任意值 p-[18px] 是逃生艙,非必要不用。
  • 響應式間距建立層次py-12 md:py-16 lg:py-24 讓手機留白小、桌面留白大,是打造專業節奏感的關鍵。
  • 多語系優先用 ps-pe-ms-me-:v4 的邏輯屬性能在 RTL 語言自動翻轉,比寫死 pl-pr- 更穩健。
  • 善用 --spacing 統一基準:需要全站等比縮放時,在 @theme 覆寫一次 --spacing 即可,別逐個 class 硬改。

小結

這是 TailwindCSS 完整教學 系列的第十二篇。上一篇 《定位系統》 我們把「脫離文件流」的定位世界講透——用 relativeabsolutefixedsticky 決定定位模式、inset-* 控制偏移、z-* 與堆疊脈絡控制層疊,做出黏性導覽、徽章、彈窗這些疊層 UI。那些工具決定元素「擺在哪、疊在哪」;而這一篇則補上「留白的藝術」——讓元素之間、內容與邊框之間,有恰到好處的呼吸感。回顧幾個重點:

  • padding 管內、margin 管外p-* 是被背景色包住的內部留白、m-* 是透明的元素間距,命名法 p/m + x/y/t/r/b/l/s/e 一眼看穿方向。
  • v4 用單一 --spacing 動態推導刻度:每個刻度都是 calc(var(--spacing) * n),任意倍數如 p-13 開箱即用,p-*m-*gap-*w-* 共用基準,覆寫一次即等比縮放(v3 是靜態表、表外值不存在)。
  • 子元素間距優先 gap:flex/grid 用 gap-*(原生、支援換行、首尾乾淨),space-* 只留給純堆疊清單,兩者切勿同容器混用。
  • margin 進階招式mx-auto 置中(需搭配寬度限制)、ml-automt-auto 推擠、負值 -space-x-* 做重疊堆疊。
  • 兩大常見坑:垂直 margin 會「邊距折疊」(改用 flex-col + gap 根治)、背景色內留白必須用 padding 而非 margin。

掌握了 Flexbox、Grid、定位與間距,你已經能精準掌控元素的排列、層疊與留白。但版面上的每個元素到底該「多大」——按鈕多寬、頭像多高、容器最大寬度是多少——還沒系統化地談過。下一篇 《尺寸系統》,我們會把 w-*(width)、h-*(height)、min-w-*max-w-*size-*,以及 v4 一樣共用 --spacing 基準的尺寸刻度一次講透,看 Tailwind 如何讓「大小」也落在同一套一致的刻度上,讓你的版面從「疏密有致」再進化到「比例協調」。

BenZ Software Developer

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

本週主打

AI 自動化入門包

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

看看這個產品 →