网格

CSS 播客 - 011:网格

网页设计中非常常见的布局是标头、边栏、正文和页脚布局。

一个包含徽标和导航功能的标题,其中包含一个边栏和一个显示文章的内容区域

多年来,人们提出了许多解决此布局的方法,但借助 CSS 网格,不仅可以相对轻松地解决此问题,而且还有多种选择。网格非常适合将外在尺寸调整提供的控制与内在尺寸调整的灵活性相结合,因此非常适合此类布局。 这是因为网格是一种专为二维内容设计的布局方法。也就是说,同时按行和列进行布局。

创建网格布局时,您需要定义包含行和列的网格。然后,您将项目放置到该网格上,或者允许浏览器将项目自动放置到您创建的单元格中。 网格布局涉及的内容很多,但只要了解可用的内容,您很快就能制作出网格布局。

概览

那么,网格有哪些用途呢? 网格布局具有以下功能。 您可以在本指南中了解所有这些平台。

  1. 可以使用行和列定义网格。 您可以选择如何调整这些行轨道和列轨道的大小,也可以让它们根据内容的大小做出反应。
  2. 网格容器的直接子项将自动放置到此网格上。
  3. 或者,您也可以将商品放置在所需的确切位置。
  4. 您可以为网格上的线条和区域命名,以便更轻松地放置内容。
  5. 网格容器中的剩余空间可以在轨道之间分配。
  6. 网格项可以在其区域内对齐。

网格术语

由于这是 CSS 首次拥有真正的布局系统,因此网格引入了许多新术语。

网格线

网格由水平线和垂直线组成。 如果网格有四列,则会有五条列线,包括最后一列后面的那条列线。

行号从 1 开始,编号方式遵循组件的书写模式和文字方向。 这意味着,在从左到右书写的语言(例如英语)中,列线 1 将位于左侧;而在从右到左书写的语言(例如阿拉伯语)中,列线 1 将位于右侧。

网格线的表示形式

网格轨道

轨道是两条网格线之间的空间。 行轨道位于两条行线之间,列轨道位于两条列线之间。 创建网格时,我们会通过为轨道分配大小来创建这些轨道。

网格轨道的一种表示形式

网格单元

网格单元格是网格上由行轨道和列轨道相交定义的最小空间。 它就像表格单元格或电子表格中的单元格一样。 如果您定义了网格,但未放置任何项,系统会自动将每个项放置到每个已定义的网格单元中。

网格单元的表示形式

网格区域

多个网格单元格。 网格区域是通过使某个项目跨越多个轨道来创建的。

网格区域的表示形式

缺口

轨道之间的排水沟或小巷。 出于调整大小的目的,这些轨道的作用与常规轨道类似。 您无法将内容放置到间隙中,但可以将网格项跨越间隙放置。

带间隙的网格的表示形式

网格容器

应用了 display: grid 的 HTML 元素,因此会为直接子元素创建新的网格格式设置上下文。

.container {
  display: grid;
}

网格项

网格项是网格容器的直接子项。

<div class="container">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
</div>

行和列

如需创建基本网格,您可以定义一个包含三个列轨道、两个行轨道且轨道之间间距为 10 像素的网格,如下所示。

.container {
    display: grid;
    grid-template-columns: 5em 100px 30%;
    grid-template-rows: 200px auto;
    gap: 10px;
}

此网格演示了术语部分中描述的许多内容。它有三个列轨道。 每个轨道使用不同的长度单位。 它有两条行轨道,一条使用长度单位,另一条使用 auto。 当用作轨道尺寸时,auto 可以视为与内容一样大。 轨道默认会自动调整大小。

如果具有 .container 类的元素有子项,这些子项将立即在此网格上布局。您可以在以下演示中查看此功能的实际效果:

Chrome 开发者工具中的网格叠加层可帮助您了解网格的各个部分。

在 Chrome 中打开演示。 检查具有灰色背景且 ID 为 container 的元素。 通过选择 DOM 中 .container 元素旁边的网格徽章来突出显示网格。 在“布局”标签页下的叠加层显示设置中,从下拉菜单中选择显示网格线编号,即可在网格上看到网格线编号。

如字幕和说明中所述
Chrome 开发者工具中突出显示的网格,显示了行号、单元格和轨道。

固有尺寸关键字

除了尺寸单位部分中所述的长度和百分比尺寸外,网格轨道还可以使用固有尺寸关键字。这些关键字在 Box Sizing 规范中定义,可在 CSS 中添加其他调整框大小的方法,而不仅仅是网格轨道。

  • min-content
  • max-content
  • fit-content()

min-content 关键字会使轨道尽可能小,同时不会导致轨道内容溢出。将示例网格布局更改为具有三个列轨道,且所有列轨道的大小均为 min-content,这意味着这些列轨道将变得与轨道中最长的字词一样窄。

max-content 关键字的效果相反。 轨道将变得足够宽,以便所有内容显示在一个长长的连续字符串中。 这可能会导致溢出,因为字符串不会换行。

fit-content() 函数最初的行为与 max-content 类似。不过,一旦轨道达到您传递给函数的大小,内容就会开始换行。因此,如果 max-content 大小小于 10em,fit-content(10em) 将创建一个小于 10em 的轨道,但绝不会大于 10em。

在下一个演示中,尝试通过更改网格轨道的大小来使用不同的固有大小调整关键字。

fr 单位

我们有现有的长度维度、百分比,以及这些新关键字。 还有一种特殊的尺寸调整方法,仅适用于网格布局。 这是 fr 单位,一种灵活的长度,用于描述网格容器中可用空间的一部分。

fr 单位的工作方式与在 flexbox 中使用 flex: auto 类似。它会在布局完项目后分配空间。 因此,若要让三个列都获得相同的可用空间份额,请执行以下操作:

.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}

由于 fr 单位会共享可用空间,因此可以将其与固定大小的间距或固定大小的轨道结合使用。如需让某个组件包含一个固定大小的元素,并让第二个轨道占据剩余的所有空间,您可以将 grid-template-columns: 200px 1fr 用作轨道列表。

如果为 fr 单位使用不同的值,则会按比例共享空间。 值越大,获得的备用空间越多。 在以下演示中,更改第三个轨的值。

minmax() 函数

Browser Support

  • Chrome: 57.
  • Edge: 16.
  • Firefox: 52.
  • Safari: 10.1.

Source

此函数表示您可以为轨道设置最小大小和最大大小。 这可能非常有用。 如果我们采用之前分配剩余空间的 fr 单位示例,则可以使用 minmax() 将其写为 minmax(auto, 1fr)。网格会查看内容的固有大小,然后在为内容提供足够的空间后分配可用空间。这意味着,您可能无法获得在网格容器中平均分配所有可用空间的轨道。

如需强制轨道在网格容器中占据相等的空间(不包括间隙),请使用 minmax。 将 1fr(作为轨道大小)替换为 minmax(0, 1fr)。这样一来,轨道的大小下限为 0,而不是 min-content 大小。然后,网格会占用容器中的所有可用大小,减去任何间隙所需的大小,并根据您的 fr 单位分配剩余空间。

repeat() 表示法

Browser Support

  • Chrome: 57.
  • Edge: 16.
  • Firefox: 76.
  • Safari: 10.1.

Source

如果您想创建 12 列的轨道网格,且各列宽度相等,可以使用以下 CSS。

.container {
    display: grid;
    grid-template-columns:
      minmax(0,1fr),
      minmax(0,1fr),
      minmax(0,1fr),
      minmax(0,1fr),
      minmax(0,1fr),
      minmax(0,1fr),
      minmax(0,1fr),
      minmax(0,1fr),
      minmax(0,1fr),
      minmax(0,1fr),
      minmax(0,1fr),
      minmax(0,1fr);
}

或者,您也可以使用 repeat() 将其写出:

.container {
    display: grid;
    grid-template-columns: repeat(12, minmax(0,1fr));
}

您可以使用 repeat() 函数重复播放曲目列表中的任何部分。例如,您可以重复播放某个曲目模式。 您还可以添加一些常规轨道和一个重复部分。

.container {
    display: grid;
    grid-template-columns: 200px repeat(2, 1fr 2fr) 200px; /*creates 6 tracks*/
}

auto-fillauto-fit

您可以将所学的有关轨道尺寸调整、minmax() 和重复的所有知识结合起来,通过网格布局创建有用的模式。也许您不想指定列轨道数,而是想创建尽可能多的列轨道,只要能放入容器中即可。

您可以使用 repeat() 以及 auto-fillauto-fit 关键字来实现此目的。在以下演示中,网格将创建尽可能多的 200 像素轨道,以适应容器的大小。 在新窗口中打开演示,并查看在您更改视口大小时网格的变化情况。

在演示中,我们会尽可能多地添加轨道。 不过,轨道并不灵活。 您会在结尾处看到一个间隙,直到有足够的空间容纳另一个 200 像素轨道为止。 如果您添加 minmax() 函数,则可以请求任意数量的轨道,但最小尺寸为 200 像素,最大尺寸为 1fr。然后,网格会布局 200 像素轨道,并将剩余空间平均分配给这些轨道。

这样一来,无需任何媒体查询即可创建二维自适应布局。

auto-fillauto-fit之间存在细微差别。 在下一个演示中,使用前面介绍的语法来尝试网格布局,但网格容器中只有两个网格项。使用 auto-fill 关键字,您可以看到已创建空轨道。 将关键字更改为 auto-fit,并将轨道收缩为 0 大小。 这意味着,灵活轨道现在会扩展以占用空间。

除此之外,auto-fillauto-fit 关键字的运作方式完全相同。一旦第一个轨道填满,两者之间就没有区别了。

自动展示位置

到目前为止,您已经在演示中看到网格自动放置的实际应用。 系统会按照项在来源中出现的顺序,将项放置在网格中,每个单元格放置一个项。 对于许多布局,这可能就是您需要的全部内容。 如果您需要更精细的控制,可以尝试以下几种方法。首先是调整自动放置布局。

将商品放置在列中

网格布局的默认行为是沿行放置项。 您可以改为使用 grid-auto-flow: column 使商品放置到列中。您需要定义行轨道,否则项将创建固有的列轨道,并以一个长行的形式进行布局。

这些值与文档的书写模式有关。 行始终按照文档或组件的书写模式中句子的运行方向运行。 在下一个演示中,您可以更改 grid-auto-flow 的值和 writing-mode 属性的模式。

跨轨道

您可以使自动放置布局中的部分或全部项跨越多个轨道。使用 span 关键字加上要跨越的行数作为 grid-column-endgrid-row-end 的值。

.item {
    grid-column-end: span 2; /* will span two lines, therefore covering two tracks */
}

由于您未指定 grid-column-start,因此该值会使用 auto 的初始值,并根据自动放置规则进行放置。您还可以使用简写形式 grid-column 指定相同的内容:

.item {
    grid-column: auto / span 2;
}

填补缺口

自动放置的布局中,如果某些项跨越多个轨道,可能会导致网格中出现一些未填充的单元格。完全自动放置的网格布局的默认行为是始终向前推进。 系统会根据项在来源中的顺序或任何包含 order 属性的修改来放置项。如果空间不足以容纳某个项目,网格会留出间隙并移至下一个轨道。

下一个演示展示了此行为。 选中此复选框将应用紧凑型打包模式。 通过将 grid-auto-flow 的值设为 dense 来启用此功能。 设置此值后,网格会稍后在布局中获取项,并使用这些项来填补空白。 这可能意味着显示内容与逻辑顺序断开连接。

放置物品

您已经拥有 CSS 网格提供的许多功能。 现在,我们来看看如何在创建的网格上放置商品。

首先要记住的是,CSS 网格布局基于编号的网格线。将内容放置到网格中的最简单方法是从一行放置到另一行。 您将在本指南中了解放置商品的其他方式,但始终可以访问这些编号的行。

您可以使用以下属性按行号放置商品:

它们具有简写形式,可让您同时设置开始行和结束行:

若要放置商品,请设置网格区域的起始线和结束线,以确定商品应放置在哪个位置。

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

.item {
    grid-column-start: 1; /* start at column line 1 */
    grid-column-end: 4; /* end at column line 4 */
    grid-row-start: 2; /*start at row line 2 */
    grid-row-end: 4; /* end at row line 4 */
}

Chrome 开发者工具可为您提供线条的直观指南,以便您检查商品放置的位置。

行编号遵循组件的书写模式和方向。在下一个演示中,更改书写模式或方向,看看项目的位置如何与文本的流向保持一致。

堆叠物品

使用基于线的定位,您可以将多个项放置在网格的同一单元格中。这意味着您可以堆叠项,也可以使一个项部分重叠另一个项。来源中靠后的项将显示在靠前的项之上。 您可以像处理定位项一样,使用 z-index 更改此堆叠顺序。

负行号

使用 grid-template-rowsgrid-template-columns 创建网格时,您创建的是所谓的显式网格。这是您已定义并为轨道指定大小的网格。

有时,您会有显示在明确网格之外的项。例如,您可以定义列轨道,然后添加多行网格项,而无需定义行轨道。默认情况下,轨道将自动调整大小。 您还可以使用 grid-column-end 放置位于显式网格之外的项。在这两种情况下,网格都会创建轨道来使布局正常运行,而这些轨道称为隐式网格

在大多数情况下,无论您使用的是隐式网格还是显式网格,都不会有任何区别。 不过,如果采用基于行的放置方式,您可能会遇到这两者之间的主要区别。

使用负行号,您可以放置显式网格末行的项目。如果您希望某个项从第一个列线延伸到最后一个列线,此属性会非常有用。 在这种情况下,您可以使用 grid-column: 1 / -1。 相应项将横跨整个显式网格。

不过,这仅适用于显式网格。 以一个包含三行自动放置项的布局为例,您希望第一个项跨越到网格的结束线。

一个包含 8 个同级网格项的边栏

您可能会认为,您可以为该商品提供 grid-row: 1 / -1。 在以下演示中,您可以看到此方法不起作用。 轨道是在隐式网格中创建的,无法使用 -1 到达网格末尾。

设置隐式轨道的大小

在隐式网格中创建的轨道默认会进行自动调整大小。 不过,如果您想控制行的大小,请使用 grid-auto-rows 属性;对于列,请使用 grid-auto-columns 属性。

如需创建最小尺寸为 10em、最大尺寸为 auto 的所有隐式行,请执行以下操作:

.container {
    display: grid;
    grid-auto-rows: minmax(10em, auto);
}

创建宽度为 100 像素和 200 像素的轨道模式的隐式列。 在这种情况下,第一个隐式列将为 100 像素,第二个为 200 像素,第三个为 100 像素,依此类推。

.container {
    display: grid;
    grid-auto-columns: 100px 200px;
}

命名网格线

如果行具有名称而不是数字,则可以更轻松地将项放置到布局中。 您可以在方括号中添加所选名称,为网格中的任何行命名。 您可以添加多个名称,并在同一方括号内用空格分隔这些名称。 为线路命名后,您可以使用名称来代替数字。

.container {
    display: grid;
    grid-template-columns:
      [main-start aside-start] 1fr
      [aside-end content-start] 2fr
      [content-end main-end]; /* a two column layout */
}

.sidebar {
    grid-column: aside-start / aside-end;
    /* placed between line 1 and 2*/
}

footer {
    grid-column: main-start / main-end;
    /* right across the layout from line 1 to line 3*/
}

网格模板区域

您还可以为网格区域命名,并将项目放置到这些命名区域中。 这是一种很棒的技术,因为它可以让您直接在 CSS 中查看组件的外观。

首先,使用 grid-area 属性为网格容器的直接子元素命名:

header {
    grid-area: header;
}

.sidebar {
    grid-area: sidebar;
}

.content {
    grid-area: content;
}

footer {
    grid-area: footer;
}

名称可以是您喜欢的任何内容,但不能是关键字 autospan。为所有项命名后,使用 grid-template-areas 属性定义每项将跨越哪些网格单元格。 每行都用英文引号括起来。

.container {
    display: grid;
    grid-template-columns: repeat(4,1fr);
    grid-template-areas:
        "header header header header"
        "sidebar content content content"
        "sidebar footer footer footer";
}

使用 grid-template-areas 时需要遵循一些规则。

  • 该值必须是完整的网格,不得包含空单元格。
  • 如需跨轨道,请重复名称。
  • 通过重复名称创建的区域必须是矩形,且不能断开。

如果您违反上述任何规则,相应值将被视为无效并舍弃。

如需在网格上留出空白,请使用 . 或多个 .(彼此之间没有空格)。例如,若要使网格中的第一个单元格为空,我可以添加一系列 . 字符:

.container {
    display: grid;
    grid-template-columns: repeat(4,1fr);
    grid-template-areas:
        "....... header header header"
        "sidebar content content content"
        "sidebar footer footer footer";
}

由于整个布局都在一个位置定义,因此使用媒体查询重新定义布局非常简单。 在下一个示例中,我创建了一个双列布局,通过重新定义 grid-template-columnsgrid-template-areas 的值,该布局会变为三列。 在新窗口中打开示例,调整视口大小,看看布局会发生什么变化。

您还可以像使用其他网格方法一样,了解 grid-template-areas 属性与 writing-mode 和方向之间的关系。

简写属性

有两个简写属性可让您一次性设置多个网格属性。在您确切了解这些属性的组合方式之前,它们可能会让您感到有些困惑。您可以自行决定是否使用缩写,也可以选择使用全称。

grid-template

Browser Support

  • Chrome: 57.
  • Edge: 16.
  • Firefox: 52.
  • Safari: 10.1.

Source

grid-template 属性是 grid-template-rowsgrid-template-columnsgrid-template-areas 的简写。 首先定义行,以及 grid-template-areas 的值。在 / 之后添加了列大小调整功能。

.container {
    display: grid;
    grid-template:
      "head head head" minmax(150px, auto)
      "sidebar content content" auto
      "sidebar footer footer" auto / 1fr 1fr 1fr;
}

grid 个房源

Browser Support

  • Chrome: 57.
  • Edge: 16.
  • Firefox: 52.
  • Safari: 10.1.

Source

grid 简写形式的用法与 grid-template 简写形式完全相同。以这种方式使用时,它会将接受的其他网格属性重置为初始值。完整的一组为:

  • grid-template-rows
  • grid-template-columns
  • grid-template-areas
  • grid-auto-rows
  • grid-auto-columns
  • grid-auto-flow

您也可以使用以下简写形式来定义隐式网格的行为,例如:

.container {
    display: grid;
    grid: repeat(2, 80px) / auto-flow  120px;
}

子网格

任何网格项也可以通过添加 display: grid 成为自己的网格容器。默认情况下,此嵌套网格具有自己的轨道大小,与父网格分开。通过使用 subgrid,子网格容器将继承父网格的轨道尺寸、网格线名称和间隙,从而更轻松地使用共享网格线对齐项。

如需在嵌套网格上使用父网格的网格列,请设置 grid-template-columns: subgrid。如需在嵌套网格上使用父网格的行,请设置 grid-template-rows: subgrid。您还可以将 subgrid 同时用于行和列。

在以下演示中,有一个类为 gallery 的网格,其中包含一些灵活的列。由于它没有 grid-template-rows 定义,因此行大小调整来自内容。图库中的网格项也是网格容器,这些容器设置为从下一个可用行 (auto) 开始,并跨越两个轨道。最后,子网格用于 grid-template-rows 属性,该属性允许单独的 gallery-item 网格共享相同的网格轨道尺寸。如果您将此行注释掉,就会发现字幕不再对齐。

将子网格应用于列和行

如果将子网格同时应用于行和列,则子网格会在两个维度上使用父网格的网格轨道。在以下代码段中,有一个显式网格,其中包含 4 列和 4 行,且轨道大小各不相同。

.container {
  display: grid;
  gap: 1em;
  grid-template-columns: auto 2fr 1fr auto;
  grid-template-rows: 5fr 1fr 2fr 1fr;
}

其中一个网格项还具有 display: grid,并设置为跨越父级网格的两列和三行。在添加 subgrid 值之前,嵌套网格中的项与父网格中的网格项不对齐。

.subgrid-container {
  display: grid;
  grid-column: auto / span 2;
  grid-row: auto / span 3;
}

演示了不使用 subgrid 会如何导致网格项的内容与父网格不对齐。

应用子网格后,子网格内的网格项会继承父网格上设置的间隙,并使用父网格的列和轨道来排列其网格项。

.subgrid-container {
  display: grid;
  grid-column: auto / span 2;
  grid-row: auto / span 3;
  grid-template-columns: subgrid;
  grid-template-rows: subgrid;
}

演示了应用 subgrid 后,网格项的内容如何与父网格对齐。

在子网格中,您可以为任何网格项应用相同的属性和值。例如,您可以扩展子网格中的网格项,使其占据两个网格列。

.featured-subgrid-item {
  grid-column: span 2;
}

演示如何使子网格项跨越父网格中的多个列轨道。

这也适用于网格行。

.subgrid-item {
  grid-row: span 2;
}

演示如何使子网格项跨越父网格中的多个行轨道。

以下是 CodePen 演示,其中在两个维度上都使用了子网格:

对齐

网格布局使用您在 Flexbox 指南中了解到的相同对齐属性。在网格中,以 justify- 开头的属性始终用于内联轴,即书写模式下句子运行的方向。

align- 开头的属性用于块轴,即块在书写模式下的布局方向。

分配额外空间

在此演示中,网格大于布置固定宽度轨道所需的空间。这意味着网格的内嵌维度和块维度都有空间。 尝试不同的 align-contentjustify-content 值,看看轨道会如何变化。

请注意,使用 space-between 等值时,间距会变大,并且跨越两个轨道的所有网格项也会增大,以吸收添加到间距中的额外空间。

移动内容

具有背景色的项似乎完全填充了它们所在的网格区域,因为 justify-selfalign-self 的初始值为 stretch

在演示中,更改 justify-itemsalign-items 的值,看看这会如何改变布局。 网格区域的大小不会改变,而是将项在定义的区域内移动。

检验您的掌握情况

测试您对网格的了解程度

以下哪些是 CSS 网格术语?

线形
网格由这些水平和垂直分隔线分隔。
圈子
抱歉,CSS 网格中没有圆圈的概念。
细胞
行与列的单个交叉点会创建一个网格单元格。
地区
多个单元格。
火车
抱歉,CSS 网格中没有列的概念。
差距
单元格之间的间距。
曲目
网格中的单行或单列即为轨道。
main {
  display: grid;
}

网格的默认布局方向是什么?

在未定义任何列的情况下,网格子级会像往常一样沿块方向布局。
如果存在 grid-auto-flow: column,则网格将按列布局。

auto-fitauto-fill 有什么不同?

auto-fit 会拉伸单元格以适应容器,而 auto-fill 不会。
auto-fill 会尽可能将更多内容放入模板中,而不会拉伸。Google 健身让它们保持一致。
auto-fit 会拉伸容器以适应子元素,而 auto-fill 会使子元素适应容器。
但这些属性并非如此。

什么是 min-content

与 0% 相同
0% 是父框的相对值,而 min-content 是框中文字和图片的相对值。
最小的字母
虽然有最小的字母,但字母并不是 min-content 所指的对象。
最长的字词或图片。
在“CSS is awesome”这个短语中,“awesome”一词就是 min-content

什么是 max-content

最长的句子或最大的图片。
这是盒子内容请求或指定的尺寸上限。它是最宽的句子或最宽的图片。
最长的字母。
虽然有最长的字母,但max-content指的不是字母。
最长的字词。
最长的字词是 min-content

什么是自动放置?

当网格根据浏览器启发式方法获取子项并以最佳顺序放置它们时。
没有任何浏览器会更改您的内容顺序,只有您自己的样式会这样做。
当网格子项已获得 grid-area 并放置在该单元格上时。
这是明确的展示位置,而不是系统推荐的展示位置。
当未分配的网格项在布局模板中紧随其后时。
没有明确区域的网格项将放置在下一个可用的网格单元中

判断正误:您只能在一个维度(行或列)中创建子网格。

正确
请重试。
错误
您可以使子网格项跨越多个行、多个列或同时跨越多个行和列。

资源

本指南简要介绍了网格布局规范的不同部分。如需了解详情,请参阅以下资源。