Firefox将支持CSS子网格功能

作者 | Rachel Andrew 译者 | 王强 编辑 | Yonie 之前还没有哪款浏览器支持 CSS 网格(CSS Grid)规范中的子网格(subgrid)功能,但现在开发者可以在新推出的 Firefox Nightly 中测试它了。如果你在使用 CSS 网格布局页面的话,这个功能肯定会让你非常满意。本文将介绍 CSS 子网格的概况和一些用例。

什么是子网格

子网格在语法层面,它是 grid-template-columns 和 grid-template-rows 属性的新关键字值。这些属性通常适用于一个轨道列表,或者说列出网格中的轨道大小(网格轨道是两条网格线之间的空间)。例如,下面的 CSS 代码将创建一个三列网格,其中包含一个 200px 列、一个大小为 max-content 的列以及一个 1fr 列。

grid-template-columns: 200px max-content 1fr;

关于轨道大小和网格布局的基础知识可以参阅 MDN 指南: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout 但如果我们将一个轨道定义为一个子网格,就会使用关键字 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 上创建了一个网格,直接子元素就布局在我创建的网格上,但 list item 将返回显示为 list item。

.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;
}

如图,list item 不会包含在网格布局中。 如果我们用一个 box3 类的网格创建<ul>,并将 grid-template-columns 设置为 subgrid,那么<ul>就成了一个三列的轨道网格。现在 list item 使用父级的轨道布局。 如图,list item 使用父级的网格布局。 CodePen 代码示例(需要 Firefox Nightly): https://codepen.io/rachelandrew/pen/xNVEPP?editors=1100

子网格的其他功能

其中,*-gap 属性默认继承到子网格中,但你可以在子网格上设置 gap、row-gap 或 column-gap 值来覆盖此行为。 子网格中的行将继承父网格上设置的行名称。所以你可以使用主网格上的行名称在子网格中定位项目。但你也可以为子网格单独添加行名称,这些行名称将添加到任何继承的名称中。 详细的功能介绍和代码示例可以参阅 MDN 上的子网格指南: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_layout/Subgrid

子网格的用途示例

对于已经熟悉网格布局的 Web 开发者来说,子网格在语法和新内容方面的变化是很小的。定义为子网格的网格与常规的嵌套网格几乎没什么区别,只是前者有自己的轨道列表,但它却能大大简化很多布局问题。 ** 示例一:** 例如,如果你做了一个卡片布局,并且卡片的页眉和页脚内容不均匀,你可能会希望卡片页眉和页脚在行间对齐。但使用标准的嵌套网格是做不到这一点的。因为每张卡片上的网格各自独立,所以卡片 A 中的轨道大小不能响应卡片 B 内的高度变化。 卡片内部元素不对齐 如果我们让每张卡片跨越三行,就可以将 grid-template-rows 的值更改为 subgrid。

.card {
grid-row: auto / span 3;
display: grid;
grid-template-rows: subgrid;
}

这张卡片还是跨越三行轨道,但这些行是在父级上定义的,因此它们的页脚都位于同一行。如果某一个页脚变得更高,整行都会随之升高。 CodePen 代码示例: https://codepen.io/rachelandrew/pen/pmyNZa。 卡片内部元素现在都对齐了 示例二 假设你想做一个标准的 12 列布局。如果没有子网格,你就不能在父网格上布置不是网格容器直接子元素的组件。相反,你需要小心调整嵌套组件中的轨道大小才能让布局正常。使用子网格的话,我们可以根据需要将嵌套网格选择到该父网格中。 在下面的线框示例中,所有元素都使用在主元素上定义的轨道——甚至是嵌套在两个网格内的元素都是如此,例如<nav>元素内的列表中的链接。下面的截图就是使用 Firefox Grid Inspector 显示父网格中线条的效果。 Grid Inspector 高亮显示的十二列网格效果 CodePen 代码示例: https://codepen.io/rachelandrew/pen/qGZRZd ** 示例三** 网格还有一个不太常见的用例:当你的布局中有数量不确定的重复内容时,你还想在网格内从头到尾都放置一个元素,这时候就能用上子网格了。 我们可以使用 -1 来定位显式网格的末尾,因此放置在 grid-row: 1 / -1 的项目将从第一行延伸到最后一行。下面的网格定义了两个行轨道。左边的块从第 1 列线延伸到了 -1 列线,所以跨越了两个轨道。 使用 Gird Inspector 高亮显示的显式网格 CodePen 代码示例: https://codepen.io/rachelandrew/pen/xNVqyY ** 示例四** 但在创建隐式行轨道时,因为你不知道将会多少项目,就无法使用 -1 来定位隐式网格的末尾。因为只有第一个轨道是显式轨道(网格在每个维度上总会有一个显式轨道),所以所有自动放置的项目布局好后,蓝色项目就没法延伸到最后一行。 如果没有显式网格,项目就无法延伸到最后一条线。 CodePen 代码示例: https://codepen.io/rachelandrew/pen/xNVqyY ** 示例五** 如果你把重复部分都做成具有隐式行列的子网格,则所有这些行都会适应同一个父级网格区域,而不会在父级上创建更多行。这意味着无论在子网格中添加了多少项目,你都可以拥有完全显式的父网格并知道结束线的确切位置。 只有一个问题,如果你没有为这些重复元素提供容器,那就得额外添加一个包装器;但单独包装的<div>不会有任何问题,不需要这个步骤。 左边栏现在与内容等高 CodePen 代码示例: https://codepen.io/rachelandrew/pen/oRxZJP

Firefox DevTools 和 subgrid

DevTools 团队一直在努力为 DevTools 添加很多像子网格这样的新功能,以便更好地处理复杂网格。 你现在可以使用 DevTools 高亮显示多个网格。这样更容易看清楚网格之间的排列关系。例如,你可以在上面的卡片示例中高亮显示多个网格,看看卡片示例中的行是如何与父行对齐的。 这里高亮显示了两个网格,一个在父级上,一个在子级上 在 Grid Inspector 中子网格有一个小子网格徽章,并且嵌套在其父级中。在处理复杂的网格布局时,它们能帮你区分各个网格。 团队还在开发其他功能,其中一个是在选择子网格时高亮显示父级: https://bugzilla.mozilla.org/show_bug.cgi?id=1550519

子网格功能现状

Firefox Nightly 现在已经支持子网格功能了,我们欢迎大家用它来测试。Firefox 是对这个规范的第一次实现,因此 Web 开发者的反馈对 Firefox 的实现、DevTools 和 CSS 规范本身都非常有价值。 需要更多资源可参阅 MDN 指南,我还在 Grid by Example 网站上放了更多示例(详见下方链接)。还可以参阅我之前写过的一篇文章: https://www.smashingmagazine.com/2018/07/css-grid-2/ 相关链接: Grid by Example 网站示例: https://gridbyexample.com/examples/#css-grid-level-2-examples 英文原文: https://hacks.mozilla.org/2019/06/css-grid-level-2-subgrid-is-coming-to-firefox/