子网格
CSS 网格布局模块为 grid-template-columns 和 grid-template-rows 包含一个 subgrid 值。本指南详细介绍了 subgrid 的作用,并给出了一些该功能可以解决的用例和设计模式。
Subgrid 简介
当你向网格容器添加 display: grid 时,只有直接子元素会成为网格项,然后可以放置在你创建的网格上。这些项的子元素则按正常流显示。
你可以通过将网格项设置为网格容器来“嵌套”网格。然而,这些网格独立于父网格和彼此,这意味着它们不会从父网格继承轨道尺寸。这使得将嵌套的网格项与主网格对齐变得困难。
如果你在 grid-template-columns、grid-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 的直接子元素,它也可以被放置在那个外部网格上,其列与外部网格的列对齐。行不是子网格,因此其行为与普通嵌套网格一样。父级上的网格区域会扩展到足以容纳这个嵌套网格的大小。
<div class="grid">
<div class="item">
<div class="subitem"></div>
</div>
</div>
.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 跨越的两个轨道绑定。
.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
在此示例中,行和列都被定义为子网格,将子网格在两个维度上都与父网格的轨道绑定。
.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;
}
子网格维度中没有隐式网格
如果你需要自动放置项目并且不知道将有多少项目,创建子网格时要小心,因为它会阻止创建额外的行来容纳这些项目。
看下一个示例——它使用了与上面示例中相同的父网格和子网格。子网格内部有十二个项目试图将自己自动放置到十个网格单元中。由于子网格在两个维度上都存在,额外的两个项目没有地方可去,所以它们进入了网格的最后一个轨道。这是规范中定义的行为。
<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>
.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 值,可以启用常规的隐式轨道创建,从而根据需要创建任意多行。这些行将不会与父级的轨道对齐。
<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>
.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
在父级上指定的任何 gap、column-gap 或 row-gap 值都会传递到子网格中,从而在轨道之间创建与父级相同的间距。这个默认行为可以通过在子网格容器上应用 gap-* 属性来覆盖。
在此示例中,父网格的行和列间距为 20px,而子网格的 row-gap 设置为 0。
<div class="grid">
<div class="item">
<div class="subitem"></div>
<div class="subitem2"></div>
</div>
</div>
.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 的作用类似于对元素应用负外边距,将间距的空间还给项目。

命名网格线
使用 CSS 网格时,你可以为网格上的线命名,然后根据这些名称而不是行号来定位项目。父网格上的线名称会传递到子网格中,你可以使用它们来放置项目。在下面的示例中,父级的命名线 col-start 和 col-end 被用来放置子项目。
<div class="grid">
<div class="item">
<div class="subitem"></div>
</div>
</div>
.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]
在子网格上指定的线会添加到在父级上指定的任何线之上,因此你可以使用其中一个或两者。在此示例中,一个项目使用父级线放置在下方,另一个使用子网格线放置。
<div class="grid">
<div class="item">
<div class="subitem"></div>
<div class="subitem2"></div>
</div>
</div>
.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-rows 的 subgrid 值,并可能为 grid-auto-rows 提供一个值来控制隐式轨道的尺寸。
规范
| 规范 |
|---|
| CSS 网格布局模块 Level 2 # subgrids |
浏览器兼容性
加载中…
另见
- 视频:使用 subgrid 布局表单 (2019)
- 视频:不要再等了,用 subgrid 获得更好的卡片布局 (2019)
- 视频:你好 subgrid!CSSConf.eu (2019) 演讲