图解CSS: Grid布局(Part6)

发布于 大漠

CSS 网格布局中有 显式网格隐式网格 之分,在 CSS 网格布局中可以使用 grid-template-columnsgrid-template-rowsgrid-template-areas 可以定义显式网格,并且可以定义显式网格固定的网格轨道数量,同时 grid-template-columnsgrid-template-rows 可以用来显式指定网格轨道尺寸。而在 CSS 网格布局中,可以在网格容器上使用 grid-auto-columnsgrid-auto-rowsgrid-auto-flow 可以显式定义隐式网格,并且 grid-auto-columnsgrid-auto-rows 可以用来指定隐式网格轨道的尺寸。那么在这篇文章中,主要和大家一起探讨在 CSS 网格布局中如何定义隐式网格和指定隐式网格轨道尺寸。

定义隐式网格:grid-auto-rows/columns

在 CSS 网格布局中,使用 grid-template-columnsgrid-template-rowsgrid-template-areas 定义一个网格。使用这三个属性中的任何一个,都可以显式设置网格的网格轨道的明确数量(列和行)。这种方式定义的网格被称为 显式网格。而且还可以使用 grid-template-columnsgrid-template-rows 显式设置网格轨道大小。比如:

.grid__container {
    display: grid;
    grid-template-columns: repeat(2, 200px);
    gap: 10px;
}

使用 grid-template-columns 显式创建了一个 2 x 1 网格,网格每列的网格轨道宽度是 200px

如果我们在上面这个已定义的显式网格中新增一个网格项,那么第三个网格项目会自动换行排列:

浏览器这样渲染是因为我们并没有明确地把网格项目放置到指定的网格单元格(或网格区域)上,因此它们会被 自动放置(Auto Placement) 。默认情况下,每个网格项目在行轴和列轴上的跨度(span)都是 1,所以它们都会被放置到下一个可用的网格单元格中。

后面我们将会花更多的篇幅和大家探讨网格项目自动放置的话题。

如果我们不让网格项目自动放置的话,可以通过用于网格项目的属性,比如 grid-rowgrid-columngrid-area 将网格项目指定到具体的区域:

.grid__item {
    grid-column: 5
}

这个示例,使用grid-column: 5 把第三个网格项目放置在第五列,但grid-template-columns: repeat(2, 200px) 只显式定义了两个列,为了定位第三个网格项目,此时网格将会增加三个隐式的列。如果你使用浏览器的开发者工具查看Demo,可以看到下图这样的结果:

如果你不知道 grid-columngrid-rowgrid-area 具体含义和使用方式并不重要,在后面我们会详细介绍。

也就是说,在 CSS 网格布局中,当网格项目被放置在显式网格之外,网格容器会给网格添加隐式网格线来生成隐式网格轨道。上面示例中”第三列“,”第四列“的网格轨道宽度是 0px,”第五列“网格轨道宽度是 auto,同时会创建隐式的网格线和隐式网格轨道:

正如上图所示,隐式网格线和显式网格线在一起构建成一个新的网格 ,该网格被称为隐式网格

在 CSS 网格中,除了使用 grid-column之外,还可以使用 grid-rowgrid-area 将网格项目放置到显式网格区域之外,此时同样能创建隐式网格。比如:

.grid__container {
    display: grid;
    grid-template-columns: repeat(2, 200px);
    gap: 10px;
}

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

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

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

上面这个示例,创建的隐式网格描述如下图所示:

不难发现,这两个示例中我们都引用了从未定义过的列或行,即引用了不存在的列或行,所以创建了宽度为0和高度为0的隐式网格轨道来填补空白。如果想给未定义过的网格轨道设置尺寸大小,我们可以在网格容器上使用 grid-auto-columnsgrid-auto-rows 来设置。换句话说,我们可以在网格容器上使用 grid-auto-columnsgrid-auto-rows 来指定隐式网格轨道的尺寸(即指定未被 grid-template-columnsgrid-template-rows 指定尺寸的网格轨道的尺寸)。

grid-auto-columnsgrid-auto-rows 的值可以设置为 auto<track-size>+,其中auto是其初始值,<track-size>值是:

<track-size>        = <track-breadth> | minmax( <inflexible-breadth> , <track-breadth> ) | fit-content( <length-percentage> )
<fixed-size>         = <fixed-breadth> | minmax( <fixed-breadth> , <track-breadth> ) | minmax( <inflexible-breadth> , <fixed-breadth> )
<track-breadth>     = <length-percentage> | <flex> | min-content | max-content | auto
<inflexible-breadth> = <length-percentage> | min-content | max-content | auto
<fixed-breadth>      = <length-percentage>
<line-names>        = '[' <custom-ident>* ']'

grid-auto-columnsgrid-auto-rows 的使用非常的简单,比如上面这个示例,可以在网格容器中显式指定隐式网格轨道的值:

.grid__container {
    display: grid;
    grid-template-columns: repeat(2, 200px);
    grid-template-rows: max-content;
    grid-auto-columns: 100px auto;
    grid-auto-rows: 60px auto;
    gap: 10px;
}

示例中使用 grid-auto-columns: 100px auto 定义了隐式网格列轨道列宽为 100pxauto(即示例中第三列列宽为60px,第四列列宽为auto);使用grid-auto-rows: 60px auto 定义了隐式网格行轨道的行高为 60pxauto(即示例中第二行行高为60px,第三行行高为auto):

正如上图所示,grid-auto-columnsgrid-auto-rows 显式指定对应隐式网格轨道尺寸,如果另有网格项目被放置在非显式网格区域之外,此时会发生什么?不妨来看另一个示例:

.grid__container {
    display: grid;
    grid-template-columns: repeat(2, 200px);
    grid-template-rows: max-content;
    grid-auto-columns: 100px auto;
    grid-auto-rows: 60px auto;
    gap: 10px;
}

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

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

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

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

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

从浏览器渲染出来的结果不难发现,重复了一次grid-auto-columns100px auto值:

.container {
    grid-auto-columns: 100px auto; 
    // 等同于
    grid-auto-columns: 100px auto 100px auto;
}

使用浏览器网格审查器,可以看到效果如下:

这一点非常有意思,我原以为额外创建出来的隐式网格轨道尺寸是 auto,结果并不是,而是重复了已显式设置的值。

上面给大家演示的是 隐式网格轨道被添加到显式网格的末端(列网格轨道和行网格轨道末端),其实隐式网格轨道还可能被扩展到显式网格的起点。比如下面这个示例:

.grid__container {
    display: grid;
    grid-template-columns: repeat(2, 200px);
    grid-template-rows: max-content;
    grid-auto-columns: 100px auto;
    grid-auto-rows: 60px auto;
    gap: 10px;
}

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

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

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

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

在这个例子中,除了第四个网格项目之外的其他网格项目,通过 grid-columngrid-rowgrid-area 结合负值网格线放置在未显式创建的网格轨道中,从而在显式网格起点创建了隐式网格:

除了上面提到的之外还有更多,更复杂的放置网格项目的方式,也有可能创建隐式网格(比如下图,图中所示为黑色虚线是显式网格,红色虚线是隐式网格):

grid-auto-rowsgrid-auto-columns 两个属性可以让我们控制隐式网格轨道尺寸:

.container {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-template-rows: 100px 100px;
    grid-gap: 20px;
    grid-auto-columns: 200px;
    grid-auto-rows: 60px;
}

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

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

上面代码定义了隐式网格轨道中的列网格轨道宽是200px,行网格轨道高是60px,而且不管网格项目是否合适:

你还可以通过使用 minmax() 函数给隐式网格轨道尺寸指定一个范围,使网格轨道尺寸设置更加灵活:

.container {
    grid-auto-columns: minmax(200px, auto);
    grid-auto-rows: minmax(60px, auto);
}

隐式网格轨道现在列宽至少有 200px,行高有 60px,但如果内容需要,会扩大。

从上面这些示例中,不难发现,使用grid-auto-rowsgrid-auto-columns 可以指定网格轨道大小,所以没有必要定义一个显式网格:

.grid__container {
    display: grid;
    grid-auto-columns: minmax(100px, auto);
    grid-auto-rows: minmax(100px, auto);
    gap: 10px;
}

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

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

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

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

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

仅仅依靠隐式网格与显式放置网格项目相结合会变得混乱笔难以理解。

但要注意,如果网格容器仅使用 grid-auto-rowsgrid-auto-columns 定义隐式网格轨道尺寸大小,并未显式使用 grid-rowgrid-columngrid-area 显式放置网格项目,此时仅会创建一个一列多行的网格:

.container {
    display: grid;
    grid-auto-columns: minmax(100px, auto);
    grid-auto-rows: minmax(100px, auto);
    gap: 10px;
}

上面这个示例,创建了一个 1 x 5 的网格:

通过这些示例,不难发现在网格布局中,grid-auto-rowsgrid-auto-columns 显式设置隐式网格轨道尺寸 与 grid-template-rowsgrid-template-columns 显式设置显式网格轨道尺寸非常相似:

但并不是所有的都相似,比如 repeat() 函数就不能用于 grid-auto-rowsgrid-auto-columns

不过,即使grid-auto-columnsgrid-auto-rows显式设置的值无效也不会影响布局,因为浏览器将会重置值为auto

更有意思的是,我们在网格容器中不显式地设置grid-auto-rowsgrid-auto-columns,也不显式设置grid-template-rowsgrid-template-columnsgrid-template-areas,只是在网格项目上显式使用 grid-rowgrid-columngrid-area 放置网格项目,也能创建隐式网格:

.grid__container {
    display: grid;
    gap: 10px;
}

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

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

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

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

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

使用浏览器网格审查器,你将会发现,上面这个示例中默认创建了一个 1 x 1 的显式网格,且因多个网格项目放置不同的位置,创建了一个隐式的网格,即最终创建了一个 5 x 3 网格(五列三行网格):

前面提到过,当 grid-template-columns 定义的显式网格无法放置所有网格项目的时候,网格项目会自动放置,比如:

.grid__container {
    display: grid;
    grid-template-columns: repeat(2, 100px);
    gap: 10px;
}

不过,如果显式在网格容器上显式设置 grid-auto-flow属性值:

.grid__container {
    display: grid;
    grid-template-columns: repeat(2, 100px);
    --grid-auto-flow: row;
    grid-auto-flow: var(--grid-auto-flow);
    gap: 10px;
}

grid-auto-flow的值为 columncolumn dense时,指定自动布局算法通过逐列填充来排列元素,在必要时增加新列。也就是说,grid-auto-flow 属性控制没有明确位置的网格项目的自动放置,一旦显式网格被填满(或者没有显式网格),自动放置也会引起隐式网格轨道的生成,即创建了隐式网格:

换句话说,在 CSS 网格中,网格容器的 grid-template-rowsgrid-template-columnsgrid-template-areas 属性定义了显式网格的固定数量的网格轨道。当网格项目被定位在这些界限之外时,网格容器会通过向网格添加隐式网格线来生成隐式网格轨道。这些网格线与显式网格线一起构建成了隐式网格。另外,网格容器的 grid-auto-rowsgrid-auto-columns 属性对这些隐式网格轨道以及由 grid-template-areas 创建但未被 grid-template-rowsgrid-template-columns 明确调整大小的任何显式网格轨道进行调整。同时,网格容器的 grid-auto-flow 属性控制没有明确位置的网格项目的自动放置。一旦显式网格被填满(或没有显式网格),自动放置也会创建隐式网格。或者可以这样来理解:

  • grid-template-rowsgrid-template-columnsgrid-template-areas 定义显式网格
  • grid-template-rowsgrid-template-columns 可以用来指定显式网格网格轨道固定数量和网格轨道尺寸
  • grid-auto-rowsgrid-auto-columnsgrid-auto-flow 定义隐式网格
  • grid-auto-rowsgrid-auto-columns 可以用来指定隐式网格网格轨道尺寸
  • grid-rowgrid-columngrid-area 将网格项目放置在显式网格之外也将会创建隐式网格,即使未使用 grid-template-rowsgrid-template-columnsgrid-template-areas 也能创建隐式网格

虽然在介绍隐式网格时多次提到 grid-auto-flow 和网格项目自动放置,但并未详细介绍。然而,网格项目自动放置或者说网格容器的grid-auto-flow 在网格布局中也是非常重要的一个技术点。grid-auto-flow 属性可以控制网格项目自动布局算法怎么运作,能精确指定在网格中被自动放置的网格项目是怎样排列的。

嗯,接下来,我们将和大家探讨网格布局中的网格项目自动放置。