CSS Grid 规范中的 subgrid 功能目前还没有在任何浏览器中发布,但现在可以在 Firefox Nightly 中进行测试。如果您已经使用过 CSS Grid 来进行任何复杂度的布局,那么您很可能会对这个功能感到兴奋。在本文中,我将介绍该功能以及它解决的一些用例。
那么 subgrid 究竟是什么?就语法而言,它是 grid-template-columns
和 grid-template-rows
属性的新的关键字值。这些属性通常接受一个轨道列表,或者换句话说,您要在网格中创建的轨道大小的列表。例如,以下 CSS 将创建一个包含三个列轨道的网格,其中包含一个 200px 的列、一个 max-content
大小的列和一个最终的 1fr
列。
grid-template-columns: 200px max-content 1fr;
您可以在 MDN 指南 Grid 布局的基本概念 中了解有关轨道大小的更多信息以及网格布局的基础知识。
但是,如果我们将轨道定义为 subgrid,则会用关键字 subgrid 替换轨道列表。
grid-template-columns: subgrid;
这指示 grid-template-columns
属性使用父元素上定义的轨道作为此嵌套网格使用的轨道大小和数量。
在下面的示例中,我有一个元素作为网格容器。它包含三个子元素 - 两个 <div>
元素和一个 <ul>
。
<div class="wrapper">
<div class="box1">A</div>
<div class="box2">B</div>
<ul class="box3">
<li>List item 1</li>
<li>List item 2</li>
<li>List item 3</li>
</ul>
</div>
我在 .wrapper
上创建了一个网格,直接子元素在创建的网格上进行布局,但是列表项返回为列表项显示。
.wrapper {
display: grid;
grid-template-columns: 2.5fr 1fr 0.5fr;
gap: 20px;
}
.box1 {
grid-column: 1;
grid-row: 1;
}
.box2 {
grid-column: 2 / 4;
grid-row: 1;
}
.box3 {
grid-column: 1 / -1;
grid-row: 2;
}

列表项不参与网格布局。
如果我们将具有 box3
类的 <ul>
设置为网格,并将 grid-template-columns
设置为 subgrid
,那么 <ul>
现在就是一个三列轨道的网格。列表项使用父元素的轨道进行布局。
.box3 {
grid-column: 1 / -1;
grid-row: 2;
<b>display: grid;</b>
<b>grid-template-columns: subgrid;</b>
}

列表项使用列表的父元素的网格。
还有一些其他不错的功能,使 subgrid 对于您可能需要构建的模式非常有用。默认情况下,*-gap
属性继承到子网格中,但是您可以通过在子网格本身设置 gap
、row-gap
或 column-gap
值来覆盖此行为。
子网格中的线将继承在父网格上设置的线名。这意味着您可以在子网格中使用主网格的线名定位项目。但是,您也可以只为子网格添加线名,这些线名将添加到任何继承的名称中。
请查看 MDN 上关于 subgrid 的指南,了解所有这些功能并查看示例代码。
subgrid 有什么用处?
就新的语法和新的学习内容而言,对于已经学习过网格布局的 Web 开发人员来说,这是一个非常小的改变。定义为 subgrid 的网格与常规嵌套网格几乎相同,只是它拥有自己的轨道列表。但是,它使许多以前难以实现的模式成为可能。
例如,如果您有一个卡片布局,而卡片的标题和页脚具有不均匀数量的内容,那么您可能希望卡片标题和页脚跨行对齐。但是,使用标准的嵌套网格,这是不可能的。每个卡片上的网格都是独立的,因此卡片 A 中的轨道大小无法响应卡片 B 内部的尺寸变化。

卡片内部元素不对齐
但是,如果我们让每张卡片跨越三行,那么我们可以将 grid-template-rows
的值更改为 subgrid。
.card {
grid-row: auto / span 3;
display: grid;
grid-template-rows: subgrid;
}
卡片仍然跨越三行轨道,但这些行是在父元素上定义的,因此每个页脚都在同一行。如果一个页脚变高,它会使整行变高。

卡片内部元素现在对齐了。
您可能希望使用标准的 12 列布局。没有 subgrid,不是网格容器直接子元素的组件无法在该父网格上进行布局。相反,您需要仔细调整嵌套组件中的轨道大小,以使布局正常工作。有了 subgrid,我们可以选择将嵌套网格加入到父网格中,直到结构需要为止。
这意味着在下面的线框示例中,所有元素都使用主元素上定义的轨道 - 即使是在两个网格内嵌套的元素,例如 <nav>
元素内的列表中的链接。下面的屏幕截图使用 Firefox 网格检查器显示了父网格的线。

网格检查器突出显示的十二列网格
subgrid 的一个不太明显的用例是帮助您在布局中存在未知数量的重复内容,并且想要能够将项目从网格的开头放置到结尾。
我们可以使用 -1
来定位显式网格的末尾,因此使用 grid-row: 1 / -1
放置的项目将从第一行扩展到最后一行。下面的网格定义了两个行轨道。左侧的块跨越两个轨道,因为它从列线 1 跨越到列线 -1。

网格检查器突出显示的显式网格
但是,如果您正在创建隐式行轨道,因为您不知道将有多少个项目,所以您不能使用 -1 来定位隐式网格的末尾。因为在第一轨道之后没有显式轨道(网格在每个维度上始终至少有一个显式轨道),所以蓝色的项目无法跨越到所有自动放置的项目都布局完成后后的结束线。

没有显式网格,项目无法扩展到结束线
如果您将重复部分设置为列的子网格,带有隐式行,所有这些行都将适合父元素的同一个网格区域,而不是在父元素上创建更多行。这意味着您可以拥有一个完全显式的父网格,并且无论子网格部分中添加了多少个项目,您都可以准确地知道结束线在哪里。
唯一的折衷方案是,如果您的标记没有用于这些重复元素的容器,则需要添加额外的包装器,但是单个包装 <div>
不会造成任何问题,并且可以实现这种模式。

侧边栏扩展到内容的高度
Firefox DevTools 和 subgrid
DevTools 团队一直在努力添加 DevTools 功能,使操作多个网格(包括 subgrid)变得更容易。
您现在可以使用 DevTools 突出显示多个网格。这对于查看网格如何彼此对齐非常有用。您可以通过在上面的卡片示例中突出显示多个网格来查看它的实际操作,让您看到卡片上的行线如何与父行对齐。

这里突出显示了两个网格,一个是父元素上的网格,另一个是子元素上的网格
在网格检查器中,子网格有一个小的子网格徽章,并且显示在父网格的内部。当您使用复杂的网格排列时,这些应该有助于您更好地识别它们。

DevTools 使您能够轻松查看子网格。
团队仍在开发功能,包括 在选择子网格时突出显示父网格的功能.
subgrid 功能的状态
subgrid 现在可以在 Firefox Nightly 中使用,因此您可以对其进行测试,我们希望您这样做。Firefox 将拥有规范的第一个实现,因此来自 Web 开发人员的反馈对于 Firefox 实现、DevTools 和 CSS 规范本身至关重要。
可以在 MDN 指南 中找到更多资源,我已经开始在我的 CSS Grid 示例网站 Grid by Example 上构建更多示例。此外,请阅读 CSS Grid Level 2: Here Comes Subgrid - 我在还没有任何实现之前写的一篇关于该规范的文章。
关于 Rachel Andrew
Rachel Andrew 是一名前端和后端 Web 开发人员,Perch CMS 背后公司的成员之一,以及 Smashing Magazine 的主编。她是 Web 技术的 Google 开发者专家,以及代表 Fronteers 的 CSS 工作组成员,在那里她是多列布局规范的共同编辑。她是 22 本书的作者,并且经常在全球各地的会议上发表演讲,您可以在 https://rachelandrew.co.uk 上找到她的最新动态。