CSSGridSubgrid前端開發布局2026

CSS Subgrid:巢狀布局的終極解決方案

整理 CSS Subgrid 的完整語法與應用場景:父子元素共享 grid tracks、卡片布局對齊、表單對齊。2026 年所有主流瀏覽器全面支援。

· 6 分鐘閱讀

CSS Grid 是 2017 年以來最重要的 CSS 布局技術,但它有個根本限制:父元素的 grid tracks(欄與列)無法被子元素繼承。巢狀的 grid 子項目,雖然自己也是一個 grid,但它只能定義自己的欄與列,沒有辨法與父層的 grid 對齊。這個限制造成了一個長期以來無解的問題:「如何讓巢狀卡片的內容,與其他卡片保持對齊?」Subgrid 解決了這個問題。2026 年,所有主流瀏覽器都支援了,是時候把它加入你的布局工具箱。


前端工程師為什麼要關心 Subgrid

在做 UI 開發時,卡片式布局是最高頻的场景之一。每個卡片內部可能有標題、內容、作者、日期、按鈕等元素。問題來了:當卡片內容長度不一致時,卡片底部很難對齊

過去的解決方式:

/* 方式一:flex 強迫撐高 */
.card {
  display: flex;
  flex-direction: column;
}
.card__content {
  flex: 1; /* 讓內容區塊自動撐滿剩餘空間 */
}

/* 方式二:固定高度(不夠靈活)*/
.card {
  height: 400px;
  overflow: hidden;
}

這些 workaround 都治標不治本。Subgrid 的做法則是:讓整個卡片的 grid 結構由外層統一管理,卡片內部的元素直接「繼承」外層定義好的欄與列。


Subgrid 的基本語法

什麼是 Subgrid

Subgrid 的核心概念:子元素使用 subgrid 關鍵字,繼承父元素的 grid tracks

/* 父層:定義一個 3 欄的 grid */
.card-grid {
  display: grid;
  grid-template-columns: 1fr 2fr 1fr;
  gap: 1.5rem;
}

/* 子層:使用 subgrid 繼承父層的 grid tracks */
.card {
  display: grid;
  grid-row: span 3; /* 佔滿 3 列 */
  grid-template-rows: subgrid; /* 關鍵:繼承父層的 3 個 row tracks */
  gap: 0; /* 由父層統一管理 gap */
}

/* 子層的內部元素,直接對齊到父層定義的 row tracks */
.card__title {
  grid-row: 1; /* 對齊到第 1 個 row track */
}
.card__content {
  grid-row: 2; /* 對齊到第 2 個 row track */
}
.card__footer {
  grid-row: 3; /* 對齊到第 3 個 row track */
}

這個例子的關鍵:card__title.card__content.card__footer 這三個元素,分別對齊到父層 .card-grid 定義的三個 row tracks。無論每個卡片的內容有多長,所有卡片的標題會在同一行,所有內容會在同一行,所有按鈕會在同一行

單方向的 Subgrid

Subgrid 可以只在其中一個方向使用:

/* 只繼承 column tracks(欄),rows 自己定義 */
.card {
  display: grid;
  grid-template-columns: subgrid; /* 繼承父層的 column tracks */
  grid-template-rows: auto 1fr auto; /* rows 自己定義 */
}

/* 只繼承 row tracks(列),columns 自己定義 */
.card {
  display: grid;
  grid-template-columns: auto 1fr auto; /* columns 自己定義 */
  grid-template-rows: subgrid; /* 繼承父層的 row tracks */
}

實際應用場景

1. 卡片布局:完美對齊的卡片底部

這是 Subgrid 最典型的應用場景:

<div class="card-grid">
  <article class="card">
    <h2 class="card__title">短標題</h2>
    <p class="card__content">內容。</p>
    <div class="card__footer">
      <button>按鈕</button>
    </div>
  </article>

  <article class="card">
    <h2 class="card__title">這是一個非常長的標題會換行</h2>
    <p class="card__content">這是更長的內容區塊。</p>
    <div class="card__footer">
      <button>按鈕</button>
    </div>
  </article>

  <article class="card">
    <h2 class="card__title">另一個標題</h2>
    <p class="card__content">適中的內容。</p>
    <div class="card__footer">
      <button>按鈕</button>
    </div>
  </article>
</div>
.card-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
  /* 定義 3 個 row tracks */
  grid-template-rows: auto 1fr auto;
}

.card {
  /* 關鍵:span 到所有 3 個 row tracks,然後用 subgrid 繼承 */
  grid-row: span 3;
  grid-template-rows: subgrid;
  /* 子元素會對齊到父層定義的 3 個 row tracks */
}

.card__title {
  grid-row: 1;
  font-size: 1.25rem;
  font-weight: 600;
}

.card__content {
  grid-row: 2;
  color: #64748b;
}

.card__footer {
  grid-row: 3;
  margin-top: auto; /* 對齊到底部 */
}

效果:無論中間那個卡片的內容有多長,三個卡片的標題都在同一行、按鈕都在同一行。

2. 表單對齊:標籤和輸入框對齊

過去要對齊表單的標籤和輸入框,通常需要固定寬度或 flex:

/* 過去的做法 */
.form-row {
  display: flex;
  align-items: center;
}
.form-row label {
  width: 120px; /* 固定寬度,不夠靈活 */
}
.form-row input {
  flex: 1;
}

Subgrid 的做法:

<form class="form">
  <div class="form-row">
    <label for="name">姓名</label>
    <input type="text" id="name" placeholder="張三" />
  </div>
  <div class="form-row">
    <label for="email">電子郵件地址(很長的標籤)</label>
    <input type="email" id="email" placeholder="a@example.com" />
  </div>
  <div class="form-row">
    <label for="phone">電話</label>
    <input type="tel" id="phone" placeholder="0912345678" />
  </div>
</form>
.form {
  display: grid;
  grid-template-columns: auto 1fr; /* 標籤欄 + 輸入框欄 */
  gap: 0.75rem;
  /* 定義多個 row tracks,每個 row track 的高度由內容決定 */
  grid-template-rows: subgrid;
  grid-row: span 3; /* 表單有 3 個表單行 */
}

.form-row {
  display: grid;
  grid-template-columns: subgrid; /* 繼承父層的 column tracks */
  gap: 0.5rem;
  align-items: center;
}

.form-row label {
  /* 對齊到第一個 column track */
  font-weight: 500;
}

.form-row input {
  /* 對齊到第二個 column track */
  padding: 0.5rem;
  border: 1px solid #e5e5e5;
  border-radius: 4px;
}

所有表單標籤會與其對應的輸入框完全對齊,無論標籤文字有多長。

3. 圖片牆:跨列/跨行的圖片對齊

.gallery {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(3, 200px);
  gap: 1rem;
}

.gallery-item {
  /* 讓每個 item 繼承父層的 column tracks */
  grid-column: span 2;
  grid-template-columns: subgrid;
}

.gallery-item img {
  grid-column: 1 / -1; /* 圖片撐滿 item 的所有 column tracks */
  width: 100%;
  height: 100%;
  object-fit: cover;
}

4. 與 Container Queries 搭配

Subgrid 與 Container Queries(容器查詢)是天生的一對:

.card-container {
  container-type: inline-size;
  container-name: card;
}

.card {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: subgrid;
  grid-row: span 3;
}

/* 當容器寬度 >= 400px 時,改成 2 欄布局 */
@container card (min-width: 400px) {
  .card-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

Subgrid vs 傳統 Grid

維度傳統 GridSubgrid
父子布局關係子元素獨立定義自己的 tracks子元素繼承父元素的 tracks
巢狀元件對齊需要 flex workarounds原生支援
應用場景簡單的網格布局複雜的巢狀對齊需求
程式碼簡潔度需要額外的 workaround更簡潔的佈局代碼

瀏覽器支援

2026 年,Subgrid 在所有主流瀏覽器都已經完全支援:

瀏覽器支援版本
Chrome117+
Edge117+
Safari16+
Firefox71+(從 2019 年就支援,是第一個實現 Subgrid 的瀏覽器)

不需要任何 Progressive Enhancement——如果你的用戶不是特別老的 Safari/Firefox 用戶,可以直接使用。

/* 如果你需要支援非常舊的瀏覽器 */
@supports (grid-template-columns: subgrid) {
  .card {
    grid-template-rows: subgrid;
  }
}

結語:讓 CSS 布局回到正確的抽象層次

Subgrid 的價值,不只是在於「能做到什麼」,而在於「什麼東西應該由誰來決定」。

過去在 Subgrid 出現之前,卡片內部的布局由內部決定,父層無法強制對齊。這導致了一個不好的結果:卡片被迫使用 flex: 1 或固定高度這類 workaround,來實現「視覺上對齊」的效果,但這些 workaround 本身是為了修補 CSS 的不足,而不是表達佈局的本意

Subgrid 把布局的「控制權」還給了正確的層級:父層定義整體的結構(欄與列),子層只需要把自己的內容「放進」父層定義好的結構裡

這是 CSS 布局本應有的樣子。


*## 延伸閱讀

本文是「2026 CSS 實用技術」系列文章之一。*