子网格

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

浏览器兼容性

另见