网格布局中的自动放置

除了能够将项目精确地放置到已创建的网格上之外,CSS 网格布局规范还包含控制在创建网格并且未放置某些或所有子项目时发生情况的规则。您可以通过在项目集上创建网格以最简单的方式看到自动放置的实际效果。

默认放置

如果您不为项目提供任何放置信息,它们将自动放置在网格上,每个网格单元格一个。

css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}
html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
</div>

自动放置的默认规则

如您在上述示例中看到的,如果您创建了一个网格,所有子项目都将自动布局,每个网格单元格一个。默认流程是按行排列项目。网格将把一个项目布局到第 1 行的每个单元格中。如果您使用 grid-template-rows 属性创建了其他行,则网格将继续在这些行中放置项目。如果网格在显式网格中没有足够的行来放置所有项目,则将创建新的隐式行。

调整隐式网格中行的尺寸

在隐式网格中自动创建的行默认为自动调整大小。这意味着它们将包含添加到其中的内容,而不会导致溢出。

但是,您可以使用 grid-auto-rows 属性控制这些行的尺寸。例如,要使所有创建的行都为 100 像素高,您可以使用

html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
</div>
css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  grid-auto-rows: 100px;
}

使用 minmax() 设置行大小

您可以在 minmax() 中使用您的值 grid-auto-rows,从而创建最小尺寸的行,如果内容更高,则会增长以适应内容。

html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>
    Four <br />This cell <br />Has extra <br />content. <br />Max is auto
    <br />so the row expands.
  </div>
  <div>Five</div>
</div>
css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  grid-auto-rows: minmax(100px, auto);
}

使用轨道列表设置行大小

您还可以传入一个轨道列表,它将重复。以下轨道列表将创建一个初始隐式行轨道为 100 像素,第二个为 200px。只要内容添加到隐式网格中,就会继续这样做。

html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
  <div>Six</div>
  <div>Seven</div>
  <div>Eight</div>
</div>
css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  grid-auto-rows: 100px 200px;
}

按列自动放置

您还可以要求网格按列自动放置项目。使用 grid-auto-flow 属性并将其值设置为 column。在这种情况下,网格将添加您使用 grid-template-rows 定义的行中的项目。当它填满一列时,它将移动到下一列显式列,或在隐式网格中创建一个新的列轨道。与隐式行轨道一样,这些列轨道也将自动调整大小。您可以使用 grid-auto-columns 控制隐式列轨道的尺寸,其工作方式与 grid-auto-rows 相同。

在下一个示例中,我创建了一个具有三个 200 像素高度的行轨道的网格。我正在按列自动放置,并且创建的列将是 300 像素的列宽,然后是 100 像素的列宽,直到有足够的列轨道来容纳所有项目。

css
.wrapper {
  display: grid;
  grid-template-rows: repeat(3, 200px);
  gap: 10px;
  grid-auto-flow: column;
  grid-auto-columns: 300px 100px;
}
html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
  <div>Six</div>
  <div>Seven</div>
  <div>Eight</div>
</div>

自动放置项目的顺序

网格容器可以包含多种类型的项目。一些项目可能在网格中具有指定的位置,而其他项目则可能自动放置。这很有用,如果您有一个文档顺序反映了项目在网格上的排列顺序,您可能不需要编写 CSS 规则来绝对定位所有内容。规范包含一个详细介绍网格项目放置算法的长篇章节,但是对于我们大多数人来说,只需要记住项目的一些简单规则。

顺序修改后的文档顺序

对于那些没有被赋予网格位置的项目,网格会按照规范中描述的“顺序修改后的文档顺序”进行放置。这意味着,如果您使用了order属性,项目将按照该顺序放置,而不是它们的 DOM 顺序。否则,它们将默认保持在文档源中输入的顺序。

具有放置属性的项目

网格首先会放置任何具有指定位置的项目。在下面的示例中,我有 12 个网格项目。项目 2 和项目 5 使用基于行的放置方法放置在网格上。您可以看到这些项目是如何放置的,以及其他项目如何在空格中自动放置。自动放置的项目将按照 DOM 顺序放置在已放置项目之前,它们不会从已放置项目之前的项目位置开始放置。

html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
  <div>Six</div>
  <div>Seven</div>
  <div>Eight</div>
  <div>Nine</div>
  <div>Ten</div>
  <div>Eleven</div>
  <div>Twelve</div>
</div>
css
.wrapper {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 100px;
  gap: 10px;
}
.wrapper div:nth-child(2) {
  grid-column: 3;
  grid-row: 2 / 4;
}
.wrapper div:nth-child(5) {
  grid-column: 1 / 3;
  grid-row: 1 / 3;
}

处理跨越轨道(track)的项目

在仍然利用自动放置的情况下,您可以使用放置属性。在下一个示例中,我通过设置项目 1、5 和 9(4n+1)在行和列上都跨越两个轨道来扩展布局。我使用grid-column-endgrid-row-end属性,并将它们的值设置为span 2。这意味着项目的起始行将由自动放置设置,而结束行将跨越两个轨道。

您可以看到,这会在网格中留下空隙,因为对于自动放置的项目,如果网格遇到一个无法放入轨道的项目,它将移动到下一行,直到找到一个项目可以容纳的空间。

html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
  <div>Six</div>
  <div>Seven</div>
  <div>Eight</div>
  <div>Nine</div>
  <div>Ten</div>
  <div>Eleven</div>
  <div>Twelve</div>
</div>
css
.wrapper {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 100px;
  gap: 10px;
}
.wrapper div:nth-child(4n + 1) {
  grid-column-end: span 2;
  grid-row-end: span 2;
  background-color: #ffa94d;
}
.wrapper div:nth-child(2) {
  grid-column: 3;
  grid-row: 2 / 4;
}
.wrapper div:nth-child(5) {
  grid-column: 1 / 3;
  grid-row: 1 / 3;
}

填充空隙

到目前为止,除了我们专门放置的项目之外,网格始终向前推进并保持项目的 DOM 顺序。这通常是您想要的,例如,如果您正在布局表单,您不希望标签和字段为了填充某些空隙而变得混乱。但是有时,我们正在布局没有逻辑顺序的内容,并且我们希望创建一个没有空隙的布局。

为此,请将属性grid-auto-flow及其值为dense添加到容器中。这与用于将流顺序更改为column的属性相同,因此,如果您在使用列,则需要添加这两个值grid-auto-flow: column dense

执行此操作后,网格现在将回填空隙,在它遍历网格时,它会像以前一样留下空隙,但是如果它找到一个可以放入先前空隙中的项目,它将拾取该项目并将其从 DOM 顺序中取出以将其放置在空隙中。与网格中的任何其他重新排序一样,这不会更改逻辑顺序。例如,Tab 顺序仍将遵循文档顺序。我们将在网格布局和可访问性指南中查看网格布局的潜在可访问性问题,但在创建视觉顺序和显示顺序之间的这种脱节时,您应该小心。

html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
  <div>Six</div>
  <div>Seven</div>
  <div>Eight</div>
  <div>Nine</div>
  <div>Ten</div>
  <div>Eleven</div>
  <div>Twelve</div>
</div>
css
.wrapper div:nth-child(4n + 1) {
  grid-column-end: span 2;
  grid-row-end: span 2;
  background-color: #ffa94d;
}
.wrapper div:nth-child(2) {
  grid-column: 3;
  grid-row: 2 / 4;
}
.wrapper div:nth-child(5) {
  grid-column: 1 / 3;
  grid-row: 1 / 3;
}
.wrapper {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 100px;
  gap: 10px;
  grid-auto-flow: dense;
}

匿名网格项目

规范中提到了匿名网格项目。如果您在网格容器内有一串文本,而该文本未包含在任何其他元素中,则会创建这些项目。在下面的示例中,我们有三个网格项目,假设您已将父元素的类grid设置为display: grid。第一个是匿名项目,因为它没有封闭的标记,此项目将始终通过自动放置规则处理。另外两个是包含在 div 中的网格项目,它们可能会自动放置,或者您可以使用定位方法将它们放置到网格上。

html
<div class="grid">
  I am a string and will become an anonymous item
  <div>A grid item</div>
  <div>A grid item</div>
</div>

匿名项目始终是自动放置的,因为没有办法定位它们。因此,如果由于某种原因您的网格中有一些未包装的文本,请注意它可能会出现在意外的位置,因为它将根据自动放置规则进行自动放置。

自动放置的用例

每当您有一组项目时,自动放置都很有用。这可能是没有逻辑顺序的项目,例如照片库或产品列表。在这种情况下,您可以选择使用密集打包模式来填充网格中的任何空洞。在我的图像库示例中,我有一些横向和一些纵向图像。我已将横向图像(类名为landscape)设置为跨越两个列轨道。然后我使用grid-auto-flow: dense来创建一个密集打包的网格。

尝试删除行grid-auto-flow: dense以查看内容如何重新流动并在布局中留下空隙。

自动放置还可以帮助您布局具有逻辑顺序的界面项目。一个例子是下一个示例中的定义列表。定义列表在样式方面是一个有趣的挑战,因为它们是扁平的,没有任何内容包装dtdd项目的组。在我的示例中,我允许自动放置放置项目,但是我有一些类将dt的起始位置设置为第 1 列,将dd的起始位置设置为第 2 列,这确保了术语位于一侧,定义位于另一侧 - 无论我们有多少个。

html
<div class="wrapper">
  <dl>
    <dt>Mammals</dt>
    <dd>Cat</dd>
    <dd>Dog</dd>
    <dd>Mouse</dd>
    <dt>Fish</dt>
    <dd>Guppy</dd>
    <dt>Birds</dt>
    <dd>Pied Wagtail</dd>
    <dd>Owl</dd>
  </dl>
</div>
css
dl {
  display: grid;
  grid-template-columns: auto 1fr;
  max-width: 300px;
  margin: 1em;
  line-height: 1.4;
}
dt {
  grid-column: 1;
  font-weight: bold;
}
dd {
  grid-column: 2;
}

我们目前无法使用自动放置做什么?

有一些问题经常被问到。目前,我们无法使用项目定位网格的每个其他单元格。如果您遵循关于网格上命名线的上一指南,您可能已经想到了一个相关的问题。那就是定义一个规则,该规则说“将项目自动放置到下一个名为“n”的行上”,然后网格将跳过其他行。在 CSSWG 的 GitHub 存储库中提出了一个关于此问题的问题,欢迎您添加自己的用例。

您可能会想出自动放置或网格布局任何其他部分的自己的用例。如果您这样做,请将其作为问题提出或添加到可能解决您的用例的现有问题中。这将有助于使规范的未来版本更好。