深入研究显示属性:网格一直向下
已发表: 2022-03-10display
属性系列,这次 Rachel Andrew 将看看当您使用 grid 作为 display 的值时会发生什么,并添加了有关 subgrid 如何更改该行为的信息。 今天,我们将看看当我们使用display: grid
时会发生什么,以及我们如何使用grid-template-columns
和grid-template-rows
的新 subgrid 值来允许网格一直向下通过我们的标记, 它们相互关联。
本文是研究 CSS display
属性各个方面的系列文章的一部分,是前两篇文章的后续文章:
-
display
的两个值 - 盒子生成
- 网格一直向下
当我们创建一个网格容器时会发生什么?
使用display: grid
打开 CSS 网格布局。 如果你看过本系列的第一篇文章,你就会知道这个单值属性的真正含义是display: block grid
。 我们得到一个块级框,它被定义为一个网格容器,其直接子项是网格项并参与网格布局。
如果您查看显示规范,您将在表中看到它定义了display
的所有不同值。 网格容器一词与网格规范中的网格容器定义相关联。 因此,要找出这实际上意味着什么,我们需要去那里看看。 当我们这样做时,我们对网格容器的行为得到了一些有用的说明。
网格容器被称为建立一个类似于块格式化上下文(BFC)的网格格式化上下文。 我已经为块格式化上下文写了一个详尽的指南。 在那篇文章中,您将发现关于 BFC 的两件事与网格格式化上下文相同。 浮动不会侵入网格容器,容器上的边距不会与内容的边距一起折叠。
然而,只有当我们进入网格容器时,它们才会有所不同。 网格容器的子项,不参与块和内联布局,它们是网格项,因此参与网格布局。 这意味着我们在块和内联布局中习惯的一些事情并不适用。
如果布局中的任何项目被浮动或清除,一旦项目成为网格项目, float
和clear
属性将不起作用。 vertical-align
属性无效,不能使用::first-letter
和::first-line
伪元素。
项目不能同时浮动和网格项目这一事实有助于创建后备。 当为不支持使用浮动网格的浏览器创建后备时(当支持网格时),您不需要做任何特殊的事情:浮动被覆盖。
我在关于支持没有网格的浏览器的文章中概述了这种方法。 在某些情况下,行为会出现问题,尽管这些问题可以通过使用 CSS 的另一部分来解决,如这篇文章中描述的关于网格和浮动的问题,“编辑布局、排除和 CSS 网格”。
话虽如此,如果我们只是将display
的值更改为grid
,我们不会看到布局有太大的不同。 直接子项是网格项,但是,默认情况下,我们以单列网格结束。 网格总是有一列一行。 执行此操作后我们可以看到的其余行是隐式行,即为保存内容而创建的行。

我们可以通过给属性grid-template-columns
一个值来开始形成看起来更像网格的东西。 该属性将轨道列表作为值; 如果我给它三个 1fr 轨道,我们现在会发现自己有一个三列网格,并且使用gap
属性可以让我在这些卡片之间留出间距。
我们现在有一些看起来像网格的东西:

我们示例中的每个网格项都有自己的子项。 卡片有页眉和页脚以及卡片主要内容的区域。 这些孩子是网格项目,但他们的孩子已经回到块和内联布局。 页眉、内容区域和页脚不做任何类似网格的事情。 这是因为当我们将display
的值更改为grid
时,它不会继承,而是只有子项成为网格项; 他们的孩子返回到块布局。
嵌套网格
如果一张卡片的内容比其他卡片多,则该行中的卡片会变得更高。 网格项目的align-items
的初始值为stretch
。 我们的卡片可以伸展到全高。 然而,里面的项目是正常的块和内联流,所以它们不会神奇地伸展来填满卡片。 (这就是为什么在上图中您可以看到内容较少的卡片在底部有一个间隙。)
如果我们想要它们(为了使页脚始终位于底部),我们也可以将网格项设为网格。 在这种情况下,我们只需要一个单列网格。 然后,我们可以定义行轨道,给具有类别内容的div
所在的区域,轨道大小为1fr
。 这会导致它占用容器中的所有可用空间,并将页脚推到卡片的底部。
请参阅 Rachel Andrew 的 Pen [显示:子网格不是我们想要的](https://codepen.io/rachelandrew/pen/PvQzeG)。
您可以根据需要尽可能多地进行网格嵌套。 我真的不认为它是嵌套,因为我们没有在这里创建嵌套表,而且我们通常使用已经存在的结构化 HTML 元素。 我们只是一次将display
的值更改为最适合该元素的子元素的值。 这可能是弹性布局或网格布局,但最常见的是块布局和内联布局。 在这种情况下,我们不需要做任何事情,因为这是默认情况下发生的。

对齐页眉和页脚
正如我们现在所看到的,如果我们想要将一组卡片布置在网格上,并且我们希望它们显示的高度与最高的卡片一样高,并且我们希望将页脚推到卡片的底部,我们只需要很少的 CSS . 上述示例的布局 CSS 如下:
.cards { display: grid; gap: 20px; grid-template-columns: 1fr 1fr 1fr; } article { display: grid; grid-template-rows: auto 1fr auto; row-gap: 20px; }
如果我们希望页眉和页脚的背景颜色对齐怎么办? 每张卡片都是一个网格项目,但页眉和页脚位于项目的网格中。 它们彼此没有关系,因此我们无法排列它们。 如果我们能以某种方式通过孩子继承网格,那就太好了。
如果我们可以在具有三行的父级上定义一个网格,然后将卡片放置在这三行中,并让页眉、内容和页脚分别位于其中一行。 这样,每个标题将位于同一行,因此如果一个标题变高,则整行都会变高。
我们今天在浏览器中没有很好的解决方案,但它正在开发中。 CSS Grid Layout Level 2 的 subgrid 特性将启用这种精确的模式。 您将能够在父元素上创建一个网格,然后有选择地选择行和/或列来使用该网格,而不是在完全独立于该网格的child
元素上定义一个新网格。
请注意,以下示例仅在撰写 Firefox Nightly 时有效。 grid-template-columns
和grid-template-rows
的 subgrid 值是CSS 网格规范第 2 级的新特性和一部分。 要试用此功能,请下载 Firefox Nightly 的副本。
您可以在下面的图片中看到它是如何工作的。 在第一张图片中,我在父级上创建了三行轨道,并将卡片跨越它们。 随着 Firefox Grid Inspector 突出显示网格,您可以看到父级的行与子级使用的行无关。

如果我没有在子级上定义三行,而是使用grid-template-rows
的 subgrid 值,那么卡片现在在父级上使用这些行。 您可以看到两者现在是如何对齐的,因此页眉和页脚也对齐:

我们在这里对 subgrid 所做的并不是display
的新值。 作为子网格的项目本身就是一个网格容器,因为我们在其上设置了display: grid
。 网格项的行为与通常的网格项一样。 这是常规的网格布局 - 与原始嵌套网格没有什么不同,只是它使用父级的轨道(而不是具有自己的行轨道大小的项目)。
.cards { display: grid; gap: 20px; grid-template-columns: 1fr 1fr 1fr; grid-template-rows: repeat(2,auto 1fr auto); } article { grid-row-end: span 3; display: grid; grid-template-rows: subgrid; }
这是子网格的好处; 如果您已经知道如何使用网格布局,则无需学习太多东西。 您可以在我之前在 Smashing Magazine 上发表的文章“CSS Grid Level 2: Here Comes Subgrid”中阅读其他详细信息。
昨天(2019 年 5 月23日),subgrid 登陆了 Firefox Nightly,所以我们有了grid-template-columns
和grid-template-rows
的 subgrid 值的可测试实现。 请务必获取 Nightly 的副本并尝试一下。 使用 Nightly 的副本,您可以看到在此 CodePen 中运行的最后一个示例:
请参阅数位屏:Rachel Andrew 不是我们想要的子网格。
看看您是否可以想出通过子网格功能解决的其他用例,或者您认为缺少的东西。 虽然某项功能仅在 Nightly 浏览器中可用,但如果发现某些问题,则可以对规范进行更改。 因此,请为您未来的网络开发自己提供帮助,并尝试这样的功能,以便您可以为网络平台做出贡献并使事情变得更好。
如果您认为您在 Firefox 实现中发现了错误,您可以查看 Bugzilla 上的主要实现错误,该错误链接到依赖部分中的相关问题。 如果您看不到您的问题,请尽可能创建一个简单的简化测试用例并提出错误。 如果你认为 subgrid 应该做一些事情来解决一个用例,而这在规范中没有详细说明,你可以在 CSS 工作组 GitHub 上提出一个问题,以获得潜在的增强。
怎么样display: contents
?
如果您一直在关注,您可能会认为display: contents
(如上一篇关于display
的文章中所述)可能会解决 subgrid 试图解决的问题 - 允许间接子级参与网格布局的问题。 事实并非如此,我们的卡片示例是展示差异的完美方式。
如果我们不使用display: grid
使我们的卡片成为网格布局,而是使用display: contents
删除该框,我们将在下一个 CodePen 中得到这个结果。 (尝试从.card
的规则中删除display: contents
行以查看差异。)
请参阅数位屏:Rachel Andrew 不是我们想要的子网格。
在此示例中,卡片的框已被移除,因此页眉、内容和页脚直接参与网格布局并在网格中自动放置。 这根本不是我们想要的! 处理完我上一篇文章中提到的浏览器的可访问性问题后,显示的contents
值将非常有用,但是,它解决了与我们正在探索的问题不同的问题。
更多阅读和示例
我一直在创建一些示例和演示来帮助每个人理解 subgrid。 您可以在下面的链接中尝试这些:
- CSS 网格 2 级示例
- CSS 网格级别 2:子网格来了
- 网格一直向下(演示文稿)
- 子网格的 MDN 文档