CSS 网格级别 2:子网格来了

已发表: 2022-03-10
快速总结↬ CSS Grid Level 2 已经在制定过程中,而这一级别规范的主要特点是为我们带来了 subgrid。 在本文中,Rachel Andrew 解释了这些新功能。

从 CSS Grid Layout 登陆我们的大多数浏览器到现在,我们已经过去了一年多的时间,而且 CSS 工作组已经在着手制定规范的第 2 级。 在本文中,我将解释目前该规范的工作和编辑草案的一部分。 请注意,此处的所有内容都可能会发生变化,并且目前在浏览器中均不适用。 以此作为对过程的一瞥,我相信随着我们开始看到实现初具规模,我会写出更多实用的文章。

CSS 规范级别

我们目前可以在浏览器中使用的 CSS Grid 特性来自于 CSS Grid 规范的 Level 1。 CSS 的各个部分被分解为模块; 这种模块化发生在 CSS 从 CSS 2.1 开始时,这就是为什么你有时会听到人们谈论 CSS3。 实际上,没有 CSS3。 取而代之的是一组模块,其中包含了 CSS2.1 规范中已经包含的所有内容。 CSS2.1 中存在的任何 CSS 都成为了 Level 3 模块的一部分,因此,我们有 CSS Selectors Level 3,因为选择器存在于 CSS2.1 中。

不属于 CSS2.1 的新 CSS 功能(例如 CSS 网格布局)从 Level 1 开始。CSS Grid Level 1 规范本质上是 Grid 的第一个版本。 一旦规范级别进入候选推荐状态,就不会添加主要的新功能。 这意味着浏览器和其他用户代理可以实现该规范,并且可以成为 W3C 推荐。 如果要设计新功能,它们将出现在规范的新级别中。 我们在这一点上使用 CSS 网格布局。 1 级规范在 CR 中,并且已经创建了 2 级规范,以便处理新功能。 如果您想跟进规范讨论,我建议您查看编辑草稿,因为这将包含所有最新的编辑。

跳跃后更多! 继续往下看↓

CSS Grid 2 级将包含什么?

最终,级别 2 规范将包含级别 1 中的所有内容以及一些新功能。 如果您在撰写本文时查看规范,有一条注释解释说,一旦 Level 2 达到 CR,应复制所有 Level 1。

然后我们可以期待找到一些新的特性,并且网格规范的第 2 级就是关于解决 CSS 网格的子网格特性。 此功能已从 Level 1 规范中删除,以便有时间正确理解 subgrid 的用例,并有更多时间来处理它而不会阻碍 Level 1 的其余部分。在本文的其余部分,我将看看当前编辑草稿中详细介绍的子网格功能。 我们处于该功能的早期阶段,但是,这是跟进的最佳时机,并实际帮助塑造规范的开发方式。 我写这篇文章的目的是解释一些正在讨论的事情,以便您能够理解并将您的意见带到讨论中。

什么是子网格?

使用 CSS 网格布局时,您已经可以嵌套网格。 在下面的示例中,我有一个包含六列轨道和三行轨道的父网格。 我已经在这个网格上从第 2 列到第 6 行以及从第 1 行到第 3 行定位了一个项目。然后我将该项目设置为一个网格容器并定义了列轨道。

 .grid { display: grid; grid-template-columns: 1fr 2fr 1fr 2fr 1fr 2fr; grid-template-rows: auto auto auto; } .item { grid-column: 2 / 6; grid-row: 1 / 3; display: grid; grid-template-columns: 2fr 1fr 2fr 1fr; }

我们嵌套网格的轨道与父节点上的轨道没有关系。 这意味着,如果我们希望能够将嵌套网格的轨道与外部网格上的线对齐,我们必须完成这项工作并使用计算轨道大小的方法来确保所有轨道保持相等。 在上面的示例中,轨道将看起来排成一行,直到将较大尺寸的项目添加到网格的一个单元格(使其占用更多空间)。

带有显示线条的 Firefox 网格检查器的网格
一个小项目意味着轨道看起来好像它们排成一列。 (大预览)
与第一个示例一样,除了嵌套网格现在不与外部对齐。
对于一个大项目,我们可以看到轨道没有对齐。 (大预览)

对于列,通常可以绕过上述情况,主要是通过限制网格的灵活性。 您可以将fr单位列minmax(0,1fr)以便它们在进行空间分配时忽略项目大小,或者您可以重新使用百分比。 但是,这消除了使用网格的一些好处,并且当涉及到在嵌套网格中排列行时,这些方法将不起作用。

假设我们想要一个卡片布局,其中各个卡片都有页眉、正文和页脚。 我们还希望页眉和页脚在卡片上对齐。

 .cards { display: grid; grid-template-columns: 1fr 1fr 1fr; grid-gap: 20px; } .card { display: grid; grid-template-rows: auto 1fr auto; }
一个容器中的三张卡片
一组卡片(大预览)

只要每个页眉和页脚中的内容高度相同,这就会起作用。 如果我们有额外的内容,那么错觉就会被打破,页眉和页脚不再在行中对齐。

容器中的三张牌,其中一个标头比其他标高
我们无法让标题在卡片上对齐。 (大预览)

创建子网格

我们现在可以看看当前如何指定子网格特征,以及它如何解决我上面展示的问题。

注意在撰写本文时,以下代码均不适用于浏览器。 这里的目的是解释语法和概念。 最终的规范也可能会从这些细节中改变。 作为参考,我根据 2018 年 6 月 23 日提供的编辑草稿撰写了这篇文章。

要创建子网格,我们将为grid-template-rowsgrid-template-columns设置一个新值。 这些属性通常与轨道列表一起使用,它定义了行和列轨道的数量和大小。 但是,在创建子网格时,您不想指定这些轨道。 相反,您使用subgrid值告诉网格这个嵌套网格应该使用它所覆盖的网格区域跨越的轨道数量和轨道大小。

在下面的代码中,我有一个包含 6 列轨道和 3 行轨道的父网格。 嵌套网格是该父网格上的一个网格项,从第 2 列到第 6 列,从第 1 行到第 4 行。这就像我们最初的示例一样,但是,我们现在可以使用子网格。 嵌套subgrid对于grid-template-columnsgrid-template-rows都有一个 subgrid 的值。 这意味着嵌套网格现在有 4 列轨道和 2 行轨道,使用与父节点上定义的轨道相同的大小。

 .grid { display: grid; grid-template-columns: 1fr 2fr 1fr 2fr 1fr 2fr; grid-template-rows: auto auto auto; } .item { grid-column: 2 / 6; grid-row: 1 / 3; display: grid; grid-template-columns: subgrid; grid-template-rows: subgrid; }
网格图
嵌套网格使用父级上定义的轨道。 (大预览)

这意味着对父级轨道大小的任何更改都将跟随嵌套网格。 更长的单词使父网格中的一个轨道更宽会导致嵌套网格中的轨道也变得更宽,所以事情会继续排列。 这也适用于另一种方式:父网格的轨道可以根据子网格中的内容变得更宽。

一维子网格

您可以在一个维度中有一个子网格,并在另一个维度中指定轨道大小。 在下一个示例中,子网格仅在grid-template-columns上指定。 grid-template-rows属性具有指定的跟踪列表。 因此,列轨道将保留为我们在上面看到的四个轨道,但行轨道可以单独定义到父轨道。

 .grid { display: grid; grid-template-columns: 1fr 2fr 1fr 2fr 1fr 2fr; grid-template-rows: auto auto auto; } .item { grid-column: 2 / 6; grid-row: 1 / 3; display: grid; grid-template-columns: subgrid; grid-template-rows: 10em 5em 200px 200px; }

这意味着子网格的行将嵌套在父网格内,就像今天创建嵌套网格时一样。 由于我们的嵌套网格跨越父网格的两行,因此这些行中的一个或两个都需要扩展以包含子网格的内容,以免导致溢出。

您也可以在一个维度中有一个子网格,而另一个维度使用隐式轨道。 在下面的示例中,我没有指定任何行轨道,并为grid-auto-rows提供了一个值。 行将以我指定的大小在隐式网格中创建,并且与前面的示例一样,父级将需要为这些行留出空间或扩展以包含它们。

 .grid { display: grid; grid-template-columns: 1fr 2fr 1fr 2fr 1fr 2fr; grid-template-rows: auto auto auto; } .item { grid-column: 2 / 6; grid-row: 1 / 3; display: grid; grid-template-columns: subgrid; grid-auto-rows: minmax(200px, auto); }

行号和子网格

如果我们再次看一下我们的第一个示例,我们的子网格的轨道大小由两个维度的父级决定。 但是,行号在子网格中正常运行。 内联方向的第一列行是第 1 行,内联方向远端的行是第 -1 行。 您不使用父项的行号来引用子网格的行。

 .grid { display: grid; grid-template-columns: 1fr 2fr 1fr 2fr 1fr 2fr; grid-template-rows: auto auto auto; } .item { grid-column: 2 / 6; grid-row: 1 / 3; display: grid; grid-template-columns: subgrid; grid-template-rows: subgrid; } .subitem { grid-column: 2 / 4; grid-row: 2; }
一个网格图,其中另一个嵌套在里面
嵌套网格从第 1 行开始编号。(大预览)

间隙和子网格

子网格将继承父网格上设置的任何列间距或行间距,但是,这可以被子网格上指定的列间距和行间距推翻。 例如,如果父网格的column-gap设置为 20px,但子网格的column-gap设置为 0,则子网格的网格单元将在每一侧增加 10px,以将间隙减小到 0,网格线基本上沿着间隙的中间向下延伸。

我们现在可以看到 subgrid 如何帮助我们解决本文开头的第二个用例,即让卡片的页眉和页脚在卡片上对齐。

 .grid { display: grid; grid-template-columns: 1fr 1fr 1fr; grid-auto-rows: auto 1fr auto; grid-gap: 20px; } .card { grid-row: auto / span 3; /* use three rows of the parent grid */ display: grid; grid-template-rows: subgrid; grid-gap: 0; /* set the gap to 0 on the subgrid so our cards don't have gaps */ }
三张卡片的页眉和页脚对齐
卡片内部结构现已排列(大预览)

线名和子网格

父网格上的任何线名都将传递给子网格。 因此,如果我们在父网格上命名线条,我们可以根据这些线条名称定位项目。

 .grid { display: grid; grid-template-columns: [a] 1fr [b] 2fr [c] 1fr [d] 2fr [e] 1fr [f] 2fr [g]; grid-template-rows: auto auto auto; } .item { grid-column: 2 / 6; grid-row: 1 / 3; display: grid; grid-template-columns: subgrid; grid-template-rows: 10em 5em 200px 200px; } .subitem { grid-column: c / e; }
显示线名称适用于网格和子网格的图表
父项上的行名称适用于子网格。 (大预览)

您还可以将线名添加到子网格中,网格线可以有多个线名,因此这些名称将添加到线中。 要指定行名称,请在grid-template-columnsgrid-template-rowssubgrid值之后添加这些名称的列表。 如果我们采用上面的示例并向子网格线添加名称,那么子网格中的任何线都会有两个线名。

 .grid { display: grid; grid-template-columns: [a] 1fr [b] 2fr [c] 1fr [d] 2fr [e] 1fr [f] 2fr [g]; grid-template-rows: auto auto auto; } .item { grid-column: 2 / 6; grid-row: 1 / 3; display: grid; grid-template-columns: subgrid [sub-a] [sub-b] [sub-c] [sub-d] [sub-e]; grid-template-rows: 10em 5em 200px 200px; } .subitem { grid-column: c / e; }
显示子网格上的线名的图表被添加到父网格上
子网格上指定的线名称将添加到父网格的名称中。 (大预览)

隐式轨道和子网格

一旦您确定网格的维度是子网格,这将消除在该维度中具有任何其他隐式轨道的能力。 如果您添加更多可以容纳的项目,则附加项目将被放置在子网格的最后一个可用轨道中,就像在过大的网格中处理项目一样。 在子网格中创建的网格区域跨越的轨道多于可用轨道,其最后一行将设置为子网格的最后一行。

然而,如上所述,您可以让子网格的一维行为方式与普通嵌套网格完全相同,包括隐式轨道。

参与流程

CSS 工作组的工作在 GitHub 上公开进行,就像任何其他开源项目一样。 这使得跟踪工作变得更容易,因为它是邮件列表中发生的所有事情。 您可以通过在 CSS 工作组 GitHub 存储库中搜索标记为 css-grid-2 的问题来查看针对 CSS 网格规范第 2 级提出的问题。 如果您可以为这些问题中的任何一个提供想法或用例,我们将受到欢迎。

人们还要求 CSS Grid Layout 提供其他功能,并且它们没有被包含在 Level 2 中的事实并不意味着它们没有被考虑。 您可以看到产品中的功能发布级别,仅仅因为某些功能不是当前冲刺的一部分,并不意味着它永远不会发生。 开发新的 Web 平台功能往往需要比平均产品发布时间稍长的时间,但这是一个类似的过程。

这一切需要多长时间?

规范开发和浏览器实现是一个有点循环的迭代过程。 在我们看到一些浏览器实现之前,并不是需要“完成”规范。 最初的实现很可能落后于特性标志——就像最初的网格规范一样。 请留意这些出现,因为一旦有代码可以使用它,就可以更轻松地考虑这些功能!

我希望这次可能即将到来的旅行很有趣。 我很高兴 subgrid 功能正在进行中,因为我一直认为它对于 web 的完整网格布局系统至关重要,请观看此空间以获取有关该功能如何进展以及新兴浏览器实现的更多新闻。