图解CSS: Grid布局(Part10)

发布于 大漠

在 CSS 网格布局中,我们可以有很多种方法将网格项目明确的放置到指定的位置。比如:

  • 使用 grid-row-startgrid-row-endgrid-column-startgrid-column-end 指定网格线名称,放置网格项目
  • 使用 grid-row-startgrid-row-endgrid-column-startgrid-column-end 的简写属性 grid-rowgrid-column 指定网格线名称,放置网格项目
  • 使用 grid-area 指定网格名称 或 指定grid-template-areas定义的网格区域名称,放置网格项目
  • grid-row-startgrid-row-endgrid-column-startgrid-column-endgrid-rowgrid-column 指定网格线名称,并且使用 span 来指定合并的网格单元格。他们的结合来放置网格项目
  • grid-row-startgrid-row-endgrid-column-startgrid-column-end(以及其简写属性grid-rowgrid-column)或 grid-area中指定 grid-template-rowsgrid-template-columnsgrid-template-areas 定义的网格线名称,放置网格项目
  • 使用已命名的网格线名称和 span 关键词,放置网格项目
  • grid-area指定grid-template-areasgrid-template-rowsgrid-template-columns创建的网格区域名称,放置网格项目

示例代码如下:

// 方法一
.grid__item {
    grid-column-start: 2;
    grid-column-end: 3;
    grid-row-start: 2;
    grid-row-end: 3;

    // 等同于
    grid-column-start: 2;
    grid-row-start: 2;
}

// 方法二
.grid__item {
    grid-row: 2 / 4;    // ᐅ row-start / row-end;
    grid-column: 2 / 4; // ᐅ col-start / col-end;
}

// 方法三
.grid__item {
    grid-area: 2 / 2 / 4 / 4; // ᐅ row-start / col-start / row-end / col-end;
}

// 方法四
.grid__item {
    grid-row:  1 / span 2;      // ᐅ row-start / span row-span-value;
    grid-column:  1 / span 2;   // ᐅ col-start / span col-span-value;
}

// 方法五
.grid__item {
    grid-column: head-col-start / head-col-end;
    grid-row: content-row-end / footer-row-end;
}

// 方法六
.grid__item {
    grid-row: row-name row-start-number/ row-name row-end-number;
    grid-column: col-name col-start-number / span col-name col-to-span;
}

// 方法七
.grid__item {
    grid-area: header;
}

上面的方法让我们可以通过不同的姿势将网格项目明确的放置在网格系统中的位置。在这个过程中,有些网格项目并没有使用上面提到的方法来明确的放置,那么这些未明确放置的网格项目会根据一种算法来正确的放置。

在接下来的内容中,将会向大家展示这个算法是如何工作的。这样一来,下次再有元素出现在一个意外的位置时,你就不会再感到困惑,也能知道发生了什么。

为了更好的掌握自动放置算法的工作原理,我们有必要来了解一些基本概念:

  • 匿名网格项目:如果你把一些文本直接放置在一个网格容器里,而没有使用任何标签包裹它,它将是一个匿名网格项目。在 CSS 网格布局中,你不能为匿名网格项目设置样式,因为你没办法使用 CSS 选择器来选择匿名网格项目,但它仍然从其父容器中继承样式规则。另一方面,网格容器内的空格符,回车符并不会创建自己的匿名网格项目
  • 网格跨度(span)的值:网格跨度的值,指的是合并网格单元格数量,它和网格位置不同,该算法没有特别的规则来解决网格跨度的值。如果没有明确指定span的值,它将会是一个默认值,即1
  • 隐式网格:通过前面的学习,我们知道,在CSS网格系统中,使用grid-template-rowsgrid-template-columnsgrid-template-areas属性显式定义的网格被称为 显式网格。不过,要是你指定一个网格项目的位置,使其位于显式网格的边界之外,浏览器就会产生额外的网格线来放置网格项目。这些网格线和显式网格一起,就构建了 隐式网格。另外,在CSS网格系统中,自动放置网格项目的算法也会导致在隐式网格中创建额外的网格轨道(行或列)

我们在介绍 grid-auto-flow 属性的时候,得知该属性是网格自动放置算法的控制属性,而且其默认值是row。除了 row 值之外,该属性还有 columndense 两个值。换句话说,在CSS网格布局系统中,网格项目自动放置的算法是怎么工作的呢?

换句话说,网格项目自动放置算法是:

将网格项目的自动位置解析为明确的位置,确保每个网格项目都有一个明确的网格区域来放置(一个网格单元格也可以称为是一个网格区域)

注意,前面也提到过,在网格项目自动放置的算法中,网格跨度是不需要特别解决的。因为未显式指定span的值,即是默认值1。另外,如果在一个显式网格系统中没有空间放置明确指定的网格项目,就有可能根据网格自动放置算法创建隐式的网格轨道(创建隐式的行或列),从而创建一个隐式网格。

另外,网格系统中的每个网格单元格(在显式网格或隐式网格中)都可以被占用或不被占用。如果一个网格单元格被一个有明确网格位置的网格项目覆盖,该网格单元格就被占用;否则,该网格单元格就未被占用。在这个算法中,一个网格单元格的占用或未占用状态是可以被改变的。

为了帮助大家更易于理解,我们将假设grid-auto-flow的值为row。如果它被设置为column,那么在这个算法中要交换所有提到的行和列、内联轴和块轴等。

接下来,我们将通过以下步骤和大家一起来看看该算法在构建布局时遵循的所有步骤的细节(指的是自动放置网格项目算法的步骤和细节)。

步骤1:匿名网格项目的生成

当自动放置网格项目算法试图将所有网格项目放在一个网格系统内时,发生的第一件事就是创建“匿名网格项目”。在网格系统中,网格容器内的文本节点,被称为匿名网格项目。比如:

<div class="grid__container">
    <div class="grid__item"></div>
    <img src="https://picsum.photos/400/300?random=2" alt="" />
    我是一个文本节点 <!-- 该文本节点被称为匿名网格项目 -->
    <div class="grid__item"></div>
    <div class="grid__item" style="float: left"></div>
</div>

假设我们在 .grid__container 上显式定义了一个网格系统:

.grid__container {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-gap: 10px;
}

正如下图所示,蓝色框框起的网格项目被称为“匿名网格项目”:

抛开网格系统不说,网格容器中的“文本节点”,我们是无法通过具体选择器来选中他,因此,我们也无法使用网格项目相关的属性来明确指定它的位置。换句话说,他的位置是按照网格系统中自动放置的算法来指定其位置。

需要注意的是,上面示例中,除了生成了一个匿名网格项目外,网格项目放置的算法将会忽略应用于网格项目i3float属性设置。

步骤2:使用显式网格名称明确放置网格项目

对于这一步和接下来的几步,将使用一个由九个网格项目组成的网格来显示它们将如何被放置(指的是网格容器有九个子元素,即i1 ~ i9网格项目,它们是怎么被放置)。即:

<div class="grid__container">
    <div class="grid__item"></div>
    <div class="grid__item"></div>
    <div class="grid__item"></div>
    <div class="grid__item"></div>
    <div class="grid__item"></div>
    <div class="grid__item"></div>
    <div class="grid__item"></div>
    <div class="grid__item"></div>
    <div class="grid__item"></div>
</div>

i1i2 两个网格项目通过使用grid-area属性指定网格线索引号明确指定其位置,其他七个网格项目未显式明确指定放置位置:

.grid__item:nth-child(1) {
    grid-area: 1 / 2 / 2 / 3;
}

.grid__item:nth-child(2) {
    grid-area: 2 / 1 / 4 / 3;
}

该算法根据网格项目i1i2各自的grid-area属性的值来定位(放置)。该算法是:

  • 使用grid-area属性的第一个(grid-row-start)和第二个值(grid-column-start)来设置网格项目 i1i2 的“左上角”的位置
  • 使用grid-area属性的第三个(grid-row-end)和第四个值(grid-column-end)来设置网格项目 i1i2 的“右下角”的位置

步骤3:仅明确指定行位置

接下来,算法会通过使用 grid-row-startgrid-row-end (即 grid-row)来明确放置那些已明确设置了行位置的网格项目。

.grid__item:nth-child(1) {
    grid-row-start: 1;
    grid-row-end: 3;

    // 等同
    grid-row: 1 / 3;
}

.grid__item:nth-child(2) {
    grid-row-start: 1;
    grid-row-end: 2;

    // 等同
    grid-row: 1 /  2;
}

这个示例,只使用grid-row指定网格线编号来明确放置网格项目i1i2位置:

对于每个有明确行位置的网格项目(即grid-row-startgrid-row-end或简写属性grid-row明确放置的网格项目),按照顺序修改(Order-Modified)后的文档顺序。换句话说,为了确定没有明确设置的列的位置(即,没有显式使用grid-column-startgrid-column-end或它们简写属性grid-column放置网格项目),该算法根据下面模式来处理:

  • 稀疏算法(Sparse,也是默认算法:将其放置的列开始网格线设置为最早的(最小的正指数)网格线索引值,以确保此网格项目的网格区域不会与任何被占用的网格单元格重叠,并且该行超过了此步骤之前放置在此行的任何网格项目
  • 密集算法(Dense:将其放置的列开始网格线设置为最早的(最小的正指数)网格线索引值,以确保这个网格项目的网格区域不会与任何占用的网格单元格重叠

前面提到过,稀疏算法(Sparse)是默认的网格项目自动放置的默认算法。网格项目的列开始网格线开始索引号将被设置为最小的网格线索引号,以确保网格项目自己的网格区域和已经被其他网格项目占用的网格单元格之间不会有任何重叠。

我们用下面这个Demo来进一步澄清这一点:

.grid__container {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-gap: 10px;
}

.grid__item:nth-child(1) {
    grid-area: 1 / 2 / 2 / 3;
}

.grid__item:nth-child(2) {
    grid-area: 2 / 1 / 4 / 3;
}

.grid__item:nth-child(3) {
    grid-row-start: 1;
    grid-row-end: 3;
}

.grid__item:nth-child(4) {
    grid-row-start: 1;
}

上面示例中的网格项目i4并没有移动到网格项目i1的左侧,尽管它可以放在那里而没有任何重叠。这是由于该算法不允许任何明确设置了行位置但没有设置列位置的网格项目被放在该特定行中任何其他类似位置的网格项目(比如示例中的网格项目i3)之前。事实上,如果你删除应用于网格项目i3的网格线规则,那么网格项目i4将移动到网格项目i1的左边:

简而言之,网格项目i4明确的设置了行位置(grid-row-start: 1),但没有明确的列位置,最终可以被放置在网格项目i1之前,但前提是网格项目i3没有干扰(在这种情况下发生干扰是因为网格项目i3和网格项目i4一样,有明确的行位置设置,但没有列位置设置,而且和网格项目i4在同一行)。

如果你想用网格项目i4来填补网格网格i1之间的空隙,就必须将grid-auto-flow值设置为row dense

.grid__container {
    grid-auto-flow: row dense;
}

在这种情况下,列开始网格线也是从最小索引号开始,不会与其他网格项目产生任何重叠。唯一不同的是,这一次,如果在某一行有一些空位(空的网格),那么网格项目可以不重叠地放置在那些空位,而不用考虑同一行中具有相同位置规则的前一个网格项目(在这个例子中是网格项目i3)。

步骤4:确定隐式网格中的列数

接下来,该算法试图确定隐式网格中的列数。可以通过下面的步骤来完成:

  • 该算法从显式网格中的列数开始
  • 然后,它浏览所有有明确列位置的网格项目,并在隐式网格的开头和结尾增加列轨道,以容纳所有网格项目
  • 最后,它通过所有没有明确列位置的网格项目。如果所有没有明确列位置的网格项目中最大的列跨度大于显式网格的宽度,则在网格的末端增加列以适应这个列跨度

比如下面这个示例:

.grid__container {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    grid-auto-flow: row dense;
    grid-gap: 10px;
}

.grid__item:nth-child(1) {
    grid-column: 4 / span 3;
}

上面示例,默认情况之下:

.grid__container {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    grid-auto-flow: row dense;
    grid-gap: 10px;
}

创建了一个5 x 3的显式网格(由grid-template-columns:repeat(5, 1fr)),但在网格项目i1上,显式设置了:

.grid__item:nth-child(1) {
    grid-column: 4 / span 3;
}

明确指定网格项目i1的位置,网格列起始网格线是4(即grid-column-start: 4),同时该网格项目合并三个列网格单元格(span 3,相当于grid-column-end: span 3),意味着网格项目i1的列网格线结束索引号是7,就需要在显多网格的末尾再创建一列,从而创建了一个6 x 3的隐式网格:

步骤5:放置剩余的网格项目

在这一点上,网格自动放置算法已经放置了所有被明确指定位置的网格项目,以及已经知道行位置的网格项目。现在,它将定位网格系统中所有其他剩余的网格项目。

在我们聊这方面的细节之前,我们有必要了解一下自动定位光标(Auto-Placement Cursor)这个术语。它定义了网格中的当前插入点,指定为一对行和列的网格线。开始时,自动定位光标被放置在隐式网格最开始的行和列。

再一次,由grid-auto-flow属性的值决定算法模式,控制了这些网格项目的定位方式。

先来看稀疏(Sparse)算法,也就是默认行为的模式。对于每一个还没有被前面步骤定位的网格项目,则会按照顺序修改(Order Modified)的文档顺序。先来看网格项目有明确的列位置情况:

  • 将光标的列位置设置为该网格项目的列开始网格线。如果它小于光标的前一列位置,则将行的位置递增1
  • 增加光标的行位置,直到找到一个网格项目不与任何占用的网格单元格重叠的值(必要时在隐式网格中创建新的行)
  • 将该网格项目的行开始网格线设置为光标的行位置,并根据其与该位置的跨度设置为该网格项目的行结束线

如果网格项目在两个轴上都有一个自动网格位置(网格自动放置的位置):

  • 增加自动定位光标的列位置,直到这个网格项目的网格区域不与任何被占用的网格单元格重叠,或者光标的列位置,加上网格项目的列跨度,超过隐式网格的列数,这是在本算法的前面确定的
  • 如果在上一步中发现一个非重叠的位置,那么将该网格项目的行开始和列开始网格线设置为光标的位置。否则,增加自动放置光标的行位置(必要时在隐式网格中创建新的行),将其列位置设置为隐式网格中最开始的列网格线,并返回到上一步

如果上面的描述比较晦涩,我们可以这样来理解。即,如果网格项目在任一轴上没有明确的位置,算法会增加光标的列的位置,直到:

  • 已经放置的网格项目与当前的网格项目没有重叠
  • 或者光标的列位置加上网格项目的跨度超过了隐式网格中的列数

如果找到了这样一个不重叠的位置,算法会将网格项目的行开始(row-start)和列开始(column-start)设置为光标的当前位置。否则,它将行位置增加1,将列开始值设置为隐式网格中最开始的一行,并重复上一步的操作。

如果该网格项目有明确的列位置,则会:

  • 自动放置光标的列位置被设置为网格项目的列开始网格线。如果这个新位置的值小于光标之前的列位置,行位置就会增加1
  • 接下来,行的位置再增加一个,直到算法达到一个值,即网格项目不与任何被占用的网格单元格重叠。如果需要,可以向隐式网格中添加额外的行。现在,网格项目的行开始网格线被设置为光标的行位置,网格项目的行结束网格线则根据其跨度来设置

我们通过下面这个简单地示例来阐述这个算法是怎么计算的:

.grid__container {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 10px;
}

.grid__item:nth-child(1) {
    grid-area: 1 / 2 / 2 / 3;
}

.grid__item:nth-child(2) {
    grid-area: 2 / 1 / 4 / 3;
}

.grid__item:nth-child(3) {
    grid-row-start: 1;
    grid-row-end: 3;
}

.grid__item:nth-child(4) {
    grid-row-start: 1;
}

.grid__item:nth-child(7) {
    grid-column-start: 3;
    grid-column-end: 5;
}

.grid__item:nth-child(8) {
    grid-column-start: 2;
    grid-column-end: 4;
}

上面示例中的网格项目i5i6没有明确指定位置。此时,网格项目自动放置的算法在处理网格项目i5时,它没有明确的设置列或行的位置,自动定位光标被设置为第一行和第一列。网格项目i5只占用了一个网格单元格,它可以放在网格的左上角,没有任何重叠的地方。因此,该算法只是将网格项目i5放在网格的第一行第一列的位置。

下一个没有明确设置列或行位置的网格项目是i6。在这一点上,自动定位光标的列位置被增加到2。然而,第一行第二列的位置已经被网格项目i1占用。这个过程一直持续到自动定位光标到达第四列。由于没有更多的列,自动定位光标的行位置增加了1,列位置被设置为1。现在行的位置是2,列的位置是1。算法再次开始将列的位置增加1,直到到达第四列。网格第二行第四列的空间目前是空的,可以被网格项目i6占用。算法把网格项目i6放在那里,然后继续放置下一个网格项目。

而网格项目i7和网格项目i8有明确的指定列的位置。我们先来看网格项目i7。自动放置光标的列位置被设置为网格项目i7grid-column-start的值,即3。现在的行和列的位置分别是33。网格中的第三行第三列的空间目前是空的,网格项目i7可以放在那里而不会有任何重叠。因此,该算法将网格项目i7放在那里。然后重复同样的步骤来放置网格项目i8

接下来,再来看“密集”(Dense)算法,即grid-auto-flow值为dense

对于每个还没有被前面步骤明确指定位置的网格项目,按照顺序修改(Order Modified)后的文档顺序。

如果该网格项目有明确的列位置:

  • 将光标的行位置设置为隐式网格中最开始的一行。将光标的列位置设置为网格项目的列始网格线
  • 增加自动定位光标的行位置,直到找到一个网格项目不与任何被占用的网格单元格重叠的值(必要时在隐式网格中创建新的行)
  • 将该网格项目的行起始网格线索引设置为光标的行位置(也隐含地根据网格项目的跨度来设置网格项目的行结束网格索引线)

如果该网格项目在两个轴上都有一个自动放置的网格位置,则会:

  • 将光标的行和列位置设置为隐式网格中最开始的行和列网格线
  • 增加自动定位光标的列位置,直到这个网格项目的网格区域不与任何被占用的网格单元格重叠,或者光标的列位置加上网格项目的跨度溢出隐式网格中的列数,这在本算法的前面已经确定
  • 如果在上一步中发现一个非重叠的位置,那么将该网格项目的行开始和列开始网格线设置为光标的位置。否则,增加自动定位光标行的位置(必要时在隐式网格中创建新的行),将其列位置重置为隐式网格中最开始的列网格线,并返回到上一步

也就是说,当grid-auto-flow的值设置为dense时,网格项目自动放置会有所不同。当放置一个没有明确指定位置的网格项目时,在确定网格项目的位置之前,光标的当前位置被设置为隐式网格中最开始的行和列。

与前面的示例不同,网格项目i9被放置在网格项目i8的左边,因为光标的位置被重置为隐式网格中最开始的行和列网格线,而不是从最后放置的网格项目开始。此时,在寻找一个合适的位置来放置网格项目i9而不发生重叠时,光标找到了网格项目i8左边的位置并将其放置在那里。

.grid__container {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-auto-flow: row dense;
    gap: 10px;
}

.grid__item:nth-child(1) {
    grid-area: 1 / 2 / 2 / 3;
}

.grid__item:nth-child(2) {
    grid-area: 2 / 1 / 4 / 3;
}

.grid__item:nth-child(3) {
    grid-row-start: 1;
    grid-row-end: 3;
}

.grid__item:nth-child(4) {
    grid-row-start: 1;
    grid-row-end: 2;
}

.grid__item:nth-child(7) {
    grid-column-start: 3;
    grid-column-end: 5;
}

.grid__item:nth-child(8) {
    grid-column-start: 2;
    grid-column-end: 4;
}

如此一来,就有了grid-auto-flow属性的语法规则,而且该属性允许我们确定两个不同的东西:

  • 方向row(默认)或 column,定义了在需要插入自动放置网格项目时,网格要增长的方向(增长行或列)
  • 模式:稀疏(Sparse,默认的)或 密集(Dense),根据打包模式,算法将在插入自动放置的网格项目时,尝试密集(填充)或稀疏(不填充)网格中的所有洞(没有被占用的网格单元格)

因此,grid-auto-flow属性可以是row densecolumn densedense等,用来决定网格项目自动放置的所需行为。下面这个示例,可以帮助你更好的理解网格项目自动放置的算法相关原理。

.grid__container {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    grid-template-rows: repeat(4, 100px);
}

.grid__item:nth-child(1) {
    grid-row: 1;
    grid-column: 2;
}

.grid__item:nth-child(2) {
    grid-row: 2;
    grid-column: 1;
}

.grid__item:nth-child(3) {
    grid-row: 1;
    grid-column: span 2;
}

.grid__item:nth-child(4) {
    grid-row: 1;
}

.grid__item:nth-child(5) {
    grid-row: 2;
}

.grid__item:nth-child(6) {
    grid-column: 2;
}

.grid__item:nth-child(8) {
    grid-column: 3;
}

对于有明确位置的网格项目i1i2,你不需要计算任何东西,只要使用网格放置属性(比如grid-rowgrid-columngrid-area)指定网格线索引号即可。然而,对于自动放置的网格项目,这是解释如何将自动放置转换为明确位置的算法。

  • 网格项目i7和网格项目i9的两个坐标都是自动的(即没有使用网格放置属性指定网格项目)
  • 网格项目i6和网格项目i8的主轴是自动的(即只使用grid-column属性指定明确的列网格线索引值)
  • 网格项目i3、网格项目i4和网格项目i5的短轴是自动的(即使用grid-row属性指定明确的行网格线索引值)

注意,块轴(列轴)也称为主轴,指由grid-auto-flow属性决定的方向,而短轴是指和主轴相反的方向。例如,grid-auto-flow值为column时,主轴即是块轴(列轴),短轴是内联轴(行轴)。

我们按下面的过程来向大家呈现该算法(前面根据规范向大家阐述过,有五个步骤)。不过这个示例,将以更直观的方式来阐述该算法(下面给大家演示的是grid-auto-flowrow的效果)。

首先是所有非自动定位的网格项目(即有明确位置的网格项目)都应该被放在网格中。比如上面示例中的网格项目i1和网格项目i2,使用了grid-rowgrid-column明确的指定了网格项目在网格中的位置:

/* 网格项目 i1 */
.grid__item:nth-child(1) {
    grid-row: 1;
    grid-column: 2;
}

/* 网格项目 i2 */
.grid__item:nth-child(2) {
    grid-row: 2;
    grid-column: 1;
}

即,网格项目i1 位于网格的第一行第二列,网格项目i2 位于网格的第二行第一列:

接着是将自动放置的网格项目放在主轴方向,而不是自动的方向,所以它们被锁定在某一行。具体的行为是需要根据包装模式(密集还是稀疏)来决定。

稀疏(Sparse) 模式,即寻找这一行中第一个适合该网格项目的空网格区域,并且它超过了这一步骤之前在同一行中放置的任何网格项目。

比如上面示例中的网格项目i3、网格项目i4和网格项目i5

.grid__item:nth-child(3) {
    grid-row: 1;
    grid-column: span 2;
}

.grid__item:nth-child(4) {
    grid-row: 1;
}

.grid__item:nth-child(5) {
    grid-row: 2;
}
  • 网格项目i3放置在网格的第一行第三列,并且跨两列(即列的结束网格线是5
  • 网格项目i4放置在网格的第一行第五列
  • 网格项目i5放置在网格的第二行第二列

**紧密(Dense)**模式,即grid-auto-flow值为row dense。会寻找这一行中第一个适合该网格项目的空网格单元格(并不关心前面的网格项目)。比如:

.grid__container {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    grid-template-rows: repeat(4, 100px);
    grid-auto-flow: row dense;
}

.grid__item:nth-child(3) {
    grid-row: 1;
    grid-column: span 2;
}

.grid__item:nth-child(4) {
    grid-row: 1;
}

.grid__item:nth-child(5) {
    grid-row: 2;
}
  • 网格项目i3放置在第一行第三列,并且跨两列(即列的结束网格线是5
  • 网格项目i4放置在第一行第一列
  • 网格项目i5放置在第二行第二列

最后,剩下的自动放置的网格项目被指定。同样的,其行为取决于包装模式。其描述与上一步中的描述非常相似,但没有行的约束(即grid-auto-flow的有可能是denserow densecolumn dense)。

稀疏(Sparse) 模式,即寻找网格项目适合的第一个空网格区域,并且它超过了这一步之前放置的任何网格项目。这意味着,我们从最后放置的网格项目的位置开始寻找空的网格区域。例如上面示例中的:

  • 网格项目i6grid-column: 2)放置在第三行第二列
  • 网格项目i7(未明确使用指定放置网格项目的属性)放置在第三行第三列
  • 网格项目i8grid-column: 3)放置在第四行第三列
  • 网格项目i9(未明确使用指定放置网格项目的属性)放置在第四行第四列

密集(Dense) 模式,即grid-auto-flow的值为row dense。寻找网格项目适合的第一个空网格区域,始终从网格的开头开始寻找。比如:

  • 网格项目i6grid-column: 2)放置在第三行第二列
  • 网格项目i7(未明确使用指定放置网格项目的属性)放置在第一行第五列
  • 网格项目i8grid-column:3)放置在第二行第三列
  • 网格项目i9(未明确使用指定放置网格项目的属性)放置在第二行第四列

在这节内容中,通过不同的方式向大家阐述了 CSS 网格模块中网格项目自动放置算法所遵循的所有步骤。简单地说,网格项目自动放置的算法是由grid-auto-flow属性控制的。

也就是说,在 CSS 网格中除了使用明确指定网格项目位置的属性之外,还可以使用grid-auto-flow有不同模式来自动放置网格项目。到目前为止,我们所阐述的网格项目都是用不同的网格区域来放置网格项目,但网格布局中的网格项目有可能是会重叠在一起的。那么接下来的一节中,将和大家一起来探讨网格项目重叠和定位相关的知识。