网格

CSS 播客 - 第 11 集:网格

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

包含徽标和导航栏的标题,以及包含文章的边栏和内容区域

多年来,解决此布局问题的方法有很多,但使用 CSS 网格不仅相对简单,而且您还有很多选择。网格非常适合将外部尺寸提供的控制功能与内在尺寸的灵活性相结合,因此非常适合这种布局。这是因为网格是一种专为二维内容设计的布局方法。也就是说,同时以行和列的形式排列内容。

创建网格布局时,您可以定义包含行和列的网格。然后,您可以将项放置到该网格中,也可以允许浏览器将其自动放置到您创建的单元格中。网格有很多方面,但只要大致了解可用功能,您很快就能制作网格布局。

概览

那么,网格有什么用途呢? 网格布局具有以下特点。 您将在本指南中了解所有这些功能。

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

网格术语

由于这是 CSS 首次拥有真正的布局系统,因此 Grid 带来了许多新术语。

网格线

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

行从 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;
}

此网格展示了术语部分中介绍的许多内容。它有三个列轨道。 每个轨道使用不同的长度单位。它有两个行轨道,一个使用长度单位,另一个使用自动。用作轨道大小调整时,自动可视为与内容一样大。轨道默认采用自动大小。

如果类为 .container 的元素有子项,这些子项将立即在此网格上排列。您可以在下面的演示中查看此操作的实际运行情况。

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

在 Chrome 中打开演示。 检查灰色背景的元素(ID 为 container)。 在 DOM 中选择 .container 元素旁边的网格标记,以突出显示网格。 在“布局”标签页中,从下拉菜单中选择显示行号,即可在网格上查看行号。

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

内在尺寸关键字

除了尺寸单位部分中所述的长度和百分比尺寸之外,网格轨道还可以使用内在尺寸关键字。这些关键字在“边框大小”规范中定义,可在 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,而不是最小内容尺寸。然后,网格将占用容器中的所有可用大小,减去任何间隙所需的大小,并根据 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 Grid 的许多功能。现在,我们来看看如何在创建的网格中放置项。

首先要记住的是,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 像素的轨道的隐式列。 在这种情况下,第一个隐式列将为 100px,第二个为 200px,第三个为 100px,以此类推。

.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;
}

对齐

网格布局使用与 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 会尽可能将尽可能多的项放入模板中,而不会拉伸。适合宽度让它们适合。
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 并放置在该单元格上时。
这是显式展示位置,而非自动展示位置。
当未分配的网格项在布局模板中放置在相邻位置时。
没有明确区域的网格项将放置在下一个可用的网格单元格中

资源

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