子網格

Baseline 2023
新推出

自 2023 年 9 月起,此功能可在最新的裝置和瀏覽器版本上使用。此功能可能無法在較舊的裝置或瀏覽器上使用。

CSS 網格佈局模組為 grid-template-columnsgrid-template-rows 包含一個 subgrid 值。本指南詳細介紹了 subgrid 的作用,並給出了一些該功能可以解決的用例和設計模式。

Subgrid 簡介

當你向網格容器新增 display: grid 時,只有直接子元素會成為網格項,然後可以放置在你建立的網格上。這些項的子元素則按正常流顯示。

你可以透過將網格項設定為網格容器來“巢狀”網格。然而,這些網格獨立於父網格和彼此,這意味著它們不會從父網格繼承軌道尺寸。這使得將巢狀的網格項與主網格對齊變得困難。

如果你在 grid-template-columnsgrid-template-rows 或兩者上設定了 subgrid 值,巢狀的網格將使用父級上定義的軌道,而不是建立一個新的軌道列表。

例如,如果你使用 grid-template-columns: subgrid 並且巢狀網格跨越父級的三個列軌道,那麼巢狀網格將擁有三個與父網格大小相同的列軌道。雖然間距是繼承的,但可以用不同的 gap 值來覆蓋。可以從父級向子網格傳遞網格線名稱,子網格也可以宣告自己的網格線名稱。

列的 Subgrid

在下面的示例中,網格佈局有九個 1fr 的列軌道和四行至少 100px 高的行。

.item 放置在第 2 到 7 列線和第 2 到 4 行線之間。這個網格項本身透過 display: grid 被指定為一個網格,然後透過為其指定作為子網格的列軌道(grid-template-columns: subgrid)和正常定義的行,被定義為一個子網格。該子網格有五個列軌道,因為它跨越了五個列軌道。

因為 .item 是一個子網格,所以即使 .subitem 不是外部 .grid 的直接子元素,它也可以被放置在那個外部網格上,其列與外部網格的列對齊。行不是子網格,因此其行為與普通巢狀網格一樣。父級上的網格區域會擴充套件到足以容納這個巢狀網格的大小。

html
<div class="grid">
  <div class="item">
    <div class="subitem"></div>
  </div>
</div>
css
.grid {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  grid-template-rows: repeat(4, minmax(100px, auto));
}

.item {
  display: grid;
  grid-column: 2 / 7;
  grid-row: 2 / 4;
  grid-template-columns: subgrid;
  grid-template-rows: repeat(3, 80px);
}

.subitem {
  grid-column: 3 / 6;
  grid-row: 1 / 3;
}

注意,在子網格內部,行號會重新開始——在子網格內部,列線 1 是子網格的第一條線。子網格元素不繼承父網格的行號。這意味著你可以安全地佈局一個可能放置在主網格不同位置的元件,同時知道該元件上的行號將始終相同。

行的 Subgrid

此示例使用與上面相同的 HTML,但在這裡,subgrid 被用作 grid-template-rows 的值,並明確定義了列軌道。在這種情況下,列軌道的行為像一個常規的巢狀網格,但行則與 .item 跨越的兩個軌道繫結。

css
.grid {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  grid-template-rows: repeat(4, minmax(100px, auto));
}

.item {
  display: grid;
  grid-column: 2 / 7;
  grid-row: 2 / 4;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: subgrid;
}

.subitem {
  grid-column: 2 / 4;
  grid-row: 1 / 3;
}

兩個維度的 Subgrid

在此示例中,行和列都被定義為子網格,將子網格在兩個維度上都與父網格的軌道繫結。

css
.grid {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  grid-template-rows: repeat(4, minmax(100px, auto));
}

.item {
  display: grid;
  grid-column: 2 / 7;
  grid-row: 2 / 4;
  grid-template-columns: subgrid;
  grid-template-rows: subgrid;
}

.subitem {
  grid-column: 3 / 6;
  grid-row: 1 / 3;
}

子網格維度中沒有隱式網格

如果你需要自動放置專案並且不知道將有多少專案,建立子網格時要小心,因為它會阻止建立額外的行來容納這些專案。

看下一個示例——它使用了與上面示例中相同的父網格和子網格。子網格內部有十二個專案試圖將自己自動放置到十個網格單元中。由於子網格在兩個維度上都存在,額外的兩個專案沒有地方可去,所以它們進入了網格的最後一個軌道。這是規範中定義的行為。

html
<div class="grid">
  <div class="item">
    <div class="subitem">1</div>
    <div class="subitem">2</div>
    <div class="subitem">3</div>
    <div class="subitem">4</div>
    <div class="subitem">5</div>
    <div class="subitem">6</div>
    <div class="subitem">7</div>
    <div class="subitem">8</div>
    <div class="subitem">9</div>
    <div class="subitem">10</div>
    <div class="subitem">11</div>
    <div class="subitem">12</div>
  </div>
</div>
css
.grid {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  grid-template-rows: repeat(4, minmax(100px, auto));
}

.item {
  display: grid;
  grid-column: 2 / 7;
  grid-row: 2 / 4;
  grid-template-columns: subgrid;
  grid-template-rows: subgrid;
}

透過移除 grid-template-rows 值,可以啟用常規的隱式軌道建立,從而根據需要建立任意多行。這些行將不會與父級的軌道對齊。

html
<div class="grid">
  <div class="item">
    <div class="subitem">1</div>
    <div class="subitem">2</div>
    <div class="subitem">3</div>
    <div class="subitem">4</div>
    <div class="subitem">5</div>
    <div class="subitem">6</div>
    <div class="subitem">7</div>
    <div class="subitem">8</div>
    <div class="subitem">9</div>
    <div class="subitem">10</div>
    <div class="subitem">11</div>
    <div class="subitem">12</div>
  </div>
</div>
css
.grid {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  grid-template-rows: repeat(4, minmax(100px, auto));
}

.item {
  display: grid;
  grid-column: 2 / 7;
  grid-row: 2 / 4;
  grid-template-columns: subgrid;
  grid-auto-rows: minmax(100px, auto);
}

間距屬性和 Subgrid

在父級上指定的任何 gapcolumn-gaprow-gap 值都會傳遞到子網格中,從而在軌道之間建立與父級相同的間距。這個預設行為可以透過在子網格容器上應用 gap-* 屬性來覆蓋。

在此示例中,父網格的行和列間距為 20px,而子網格的 row-gap 設定為 0

html
<div class="grid">
  <div class="item">
    <div class="subitem"></div>
    <div class="subitem2"></div>
  </div>
</div>
css
.grid {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  grid-template-rows: repeat(4, minmax(100px, auto));
  gap: 20px;
}

.item {
  display: grid;
  grid-column: 2 / 7;
  grid-row: 2 / 4;
  grid-template-columns: subgrid;
  grid-template-rows: subgrid;
  row-gap: 0;
}

.subitem {
  grid-column: 3 / 6;
  grid-row: 1 / 3;
}

.subitem2 {
  background-color: rgb(0 0 0 / 0.5);
  grid-column: 2;
  grid-row: 1;
}

如果你在開發者工具的網格檢查器中檢查這一點,你會注意到子網格線位於間距的中心。將間距設定為 0 的作用類似於對元素應用負外邊距,將間距的空間還給專案。

The smaller item displays in the gap as row-gap is set to 0 on the subgrid, as seen in the firefox developer tools grid inspector.

命名網格線

使用 CSS 網格時,你可以為網格上的線命名,然後根據這些名稱而不是行號來定位專案。父網格上的線名稱會傳遞到子網格中,你可以使用它們來放置專案。在下面的示例中,父級的命名線 col-startcol-end 被用來放置子專案。

html
<div class="grid">
  <div class="item">
    <div class="subitem"></div>
  </div>
</div>
css
.grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr [col-start] 1fr 1fr 1fr [col-end] 1fr 1fr 1fr;
  grid-template-rows: repeat(4, minmax(100px, auto));
  gap: 20px;
}

.item {
  display: grid;
  grid-column: 2 / 7;
  grid-row: 2 / 4;
  grid-template-columns: subgrid;
  grid-template-rows: subgrid;
}

.subitem {
  grid-column: col-start / col-end;
  grid-row: 1 / 3;
}

你也可以在子網格上指定線名稱。這是透過在 subgrid 關鍵字後新增一個用方括號括起來的線名稱列表來實現的。例如,如果你的子網格中有四條線,要為它們全部命名,你可以使用語法 grid-template-columns: subgrid [line1] [line2] [line3] [line4]

在子網格上指定的線會新增到在父級上指定的任何線之上,因此你可以使用其中一個或兩者。在此示例中,一個專案使用父級線放置在下方,另一個使用子網格線放置。

html
<div class="grid">
  <div class="item">
    <div class="subitem"></div>
    <div class="subitem2"></div>
  </div>
</div>
css
.grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr [col-start] 1fr 1fr 1fr [col-end] 1fr 1fr 1fr;
  grid-template-rows: repeat(4, minmax(100px, auto));
  gap: 20px;
}

.item {
  display: grid;
  grid-column: 2 / 7;
  grid-row: 2 / 4;
  grid-template-columns: subgrid [sub-a] [sub-b] [sub-c] [sub-d] [sub-e] [sub-f];
  grid-template-rows: subgrid;
}

.subitem {
  grid-column: col-start / col-end;
  grid-row: 1 / 3;
}

.subitem2 {
  background-color: rgb(0 0 0 / 0.5);
  grid-column: sub-b / sub-d;
  grid-row: 1;
}

使用 Subgrid

子網格的行為與任何巢狀網格非常相似;唯一的區別是子網格的軌道尺寸是在父網格上設定的。然而,與任何巢狀網格一樣,子網格中內容的大小可以改變軌道尺寸,前提是使用了允許內容影響尺寸的軌道尺寸設定方法。在這種情況下,自動調整大小的行軌道將增長以適應主網格和子網格中的內容。

由於 subgrid 值的行為與常規巢狀網格非常相似,因此在兩者之間切換很容易。例如,如果你發現你需要一個用於行的隱式網格,你需要移除 grid-template-rowssubgrid 值,並可能為 grid-auto-rows 提供一個值來控制隱式軌道的尺寸。

規範

規範
CSS 網格佈局模組 Level 2
# subgrids

瀏覽器相容性

另見