Grid

CSS 播客 - 011:Grid

Web 设计中非常常见的布局是页眉、侧边栏、主体和页脚布局。

A header with logo and navigation with a sidebar and content area that features an article

多年来,有很多方法可以解决此布局,但借助 CSS Grid,不仅相对简单,而且您还有很多选择。Grid 非常擅长将外在尺寸调整提供的控件与内在尺寸调整的灵活性相结合,这使其成为此类布局的理想选择。这是因为 Grid 是一种专为二维内容设计的布局方法。也就是说,同时按行和列排列事物。

创建网格布局时,您可以定义具有行和列的网格。然后,将项目放置在该网格上,或允许浏览器将它们自动放置到您创建的单元格中。Grid 的内容很多,但通过概述可用的内容,您将立即制作网格布局。

概述

那么,您可以使用 Grid 做什么?网格布局具有以下功能。您将在本指南中了解所有这些功能。

  1. 可以使用行和列定义网格。您可以选择如何调整这些行和列轨道的大小,或者它们可以对内容的大小做出反应。
  2. 网格容器的直接子项将自动放置到此网格上。
  3. 或者,您可以将项目放置在您想要的精确位置。
  4. 可以命名网格上的线和区域,以使放置更容易。
  5. 网格容器中的空余空间可以在轨道之间分配。
  6. 网格项目可以在其区域内对齐。

网格术语

Grid 附带了一堆新术语,因为这是 CSS 首次拥有真正的布局系统。

网格线

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

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

A diagram representation of grid lines

网格轨道

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

A diagram representation of a grid track

网格单元格

网格单元格是网格上最小的空间,由行轨道和列轨道的交点定义。它就像表格单元格或电子表格中的单元格。如果您定义一个网格并且不放置任何项目,它们将自动布局,每个定义的网格单元格中放置一个项目。

A diagram representation of a grid cell

网格区域

多个网格单元格组合在一起。网格区域是通过使项目跨越多个轨道来创建的。

A diagram representation of a grid area

间距

轨道之间的沟槽或间隙。为了调整大小,这些间距的作用类似于常规轨道。您无法将内容放入间距中,但可以将网格项目跨越间距。

A diagram representation of a grid with gaps

网格容器

应用了 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 DevTools 中的网格叠加层可以帮助您了解网格的各个部分。

在 Chrome 中打开演示。检查具有灰色背景的元素,该元素的 ID 为 container。通过选择 DOM 中 .container 元素旁边的网格徽章来突出显示网格。在“布局”标签内,在下拉列表中选择显示行号以查看网格上的行号。

As described in the caption and instructions
在 Chrome DevTools 中突出显示的网格,显示行号、单元格和轨道。

固有尺寸调整关键字

除了尺寸单位部分中描述的长度和百分比尺寸外,网格轨道还可以使用固有尺寸调整关键字。这些关键字在 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() 函数

浏览器支持

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

来源

此函数意味着您可以为轨道设置最小和最大尺寸。这可能非常有用。如果我们以上面分配剩余空间的 fr 单位为例,则可以使用 minmax() 将其写为 minmax(auto, 1fr)。Grid 会查看内容的固有大小,然后在为内容提供足够的空间后分配可用空间。这意味着您可能无法获得每个轨道都具有网格容器中所有可用空间的相等份额。

要强制轨道占用网格容器中减去间距的相等份额空间,请使用 minmax。将作为轨道尺寸的 1fr 替换为 minmax(0, 1fr)。这使轨道的最小尺寸为 0,而不是 min-content 尺寸。然后,Grid 将获取容器中的所有可用尺寸,减去任何间距所需的尺寸,并根据您的 fr 单位共享其余部分。

repeat() 表示法

浏览器支持

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

来源

如果您想创建一个具有相等列的 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 的所有知识,使用网格布局创建一个有用的模式。也许您不想指定列轨道的数量,而是想创建尽可能多的列轨道以适应您的容器。

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

在演示中,我们获得了尽可能多的轨道。但是,轨道不是灵活的。您将在末尾获得一个间隙,直到有足够的空间容纳另一个 200 像素轨道。如果您添加 minmax() 函数,您可以请求尽可能多的轨道,最小尺寸为 200 像素,最大尺寸为 1fr。然后,Grid 会布局 200 像素轨道,并将剩余的任何空间平均分配给它们。

这将创建一个二维自适应布局,而无需任何媒体查询。

auto-fillauto-fit 之间存在细微差别。在下一个演示中,使用上面解释的语法玩网格布局,但在网格容器中只有两个网格项目。使用 auto-fill 关键字,您可以看到已创建空轨道。将关键字更改为 auto-fit,轨道将折叠为 0 大小。这意味着灵活的轨道现在会增长以占用空间。

auto-fillauto-fit 关键字在其他方面的工作方式完全相同。一旦第一个轨道被填充,它们之间就没有区别。

自动放置

到目前为止,您已经在演示中看到了网格自动放置的工作原理。项目按照它们在源代码中出现的顺序,每个单元格放置一个项目。对于许多布局,这可能是您需要的全部内容。如果您需要更多控制,那么您可能需要做几件事。首先是调整自动放置布局。

在列中放置项目

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

这些值与文档的书写模式相关。行始终在句子在文档或组件的书写模式中运行的方向上运行。在下一个演示中,您可以更改 grid-auto-flowwriting-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 Grid Layout 基于编号线的网格。将事物放置到网格上的最简单方法是将它们从一条线放置到另一条线。您将在本指南中发现其他放置项目的方法,但您始终可以访问这些编号线。

您可以使用以下属性按行号放置项目

它们有简写形式,允许您一次设置起始线和结束线

要放置您的项目,请设置应放置到的网格区域的起始线和结束线。

.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 DevTools 可以为您提供线的视觉指南,以便检查项目放置的位置。

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

堆叠项目

使用基于线的定位,您可以将项目放置到网格的同一单元格中。这意味着您可以堆叠项目,或者使一个项目部分重叠另一个项目。源代码中稍后出现的项目将显示在较早出现的项目之上。您可以像对定位项目一样,使用 z-index 更改此堆叠顺序。

负行号

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

有时,您会遇到显示在此外显式网格之外的项目。例如,您可能定义了列轨道,然后添加了多行网格项目,而从未定义行轨道。轨道默认情况下会自动调整大小。您还可以使用 grid-column-end 放置超出已定义的显式网格范围的项目。在这两种情况下,网格都会创建轨道以使布局正常工作,这些轨道称为隐式网格

大多数情况下,如果您使用隐式网格或显式网格,则不会有任何区别。但是,使用基于线的放置,您可能会遇到两者之间的主要区别。

使用负行号,您可以从显式网格的结束线放置项目。如果您希望项目从第一条列线跨越到最后一条列线,这将非常有用。在这种情况下,您可以使用 grid-column: 1 / -1。项目将一直延伸到显式网格。

但这仅适用于显式网格。采用三行自动放置项目的布局,您希望第一个项目跨越到网格的结束线。

A sidebar with 8 sibling grid items

您可能会认为您可以为该项目赋予 grid-row: 1 / -1。在下面的演示中,您可以看到这不起作用。轨道是在隐式网格中创建的,无法使用 -1 到达网格的末尾。

调整隐式轨道的大小

在隐式网格中创建的轨道默认情况下会自动调整大小。但是,如果您想控制行的尺寸调整,请使用 grid-auto-rows 属性,对于列,请使用 grid-auto-columns

要以最小尺寸 10em 和最大尺寸 auto 创建所有隐式行

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

要创建具有 100px 和 200px 宽轨道模式的隐式列。在这种情况下,第一个隐式列将为 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 和 direction 相关,与其他网格方法一样。

简写属性

有两个简写属性允许您一次设置许多网格属性。在您分解它们如何组合在一起之前,这些属性看起来可能有点令人困惑。您是想使用它们还是更喜欢使用长手属性,这取决于您。

grid-template

浏览器支持

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

来源

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 属性

浏览器支持

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

来源

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 的值以查看这如何更改布局。网格区域的大小没有改变,而是项目在定义的区域内移动。

检查您的理解情况

测试您对 Grid 的知识

以下哪些是 CSS Grid 术语?

线
网格由此水平和垂直运行的分隔符分隔。
抱歉,CSS Grid 中没有圆的概念。
单元格
行和列的单个交点创建一个网格单元格。
区域
多个单元格组合在一起。
轨道
抱歉,CSS Grid 中没有轨道的概念。
间距
单元格之间的空间。
轨道
单行或单列是网格中的轨道。
main {
  display: grid;
}

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

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

auto-fitauto-fill 之间有什么区别?

auto-fit 将拉伸单元格以适合容器,而 auto-fill 不会。
auto-fill 会将尽可能多的项目放入模板中,而不会拉伸。Fit 使它们适合。
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 并在该单元格上放置时。
那是显式放置,而不是自动放置。
当未分配的网格项目在布局模板中接下来放置时。
没有显式区域的网格项目将放置在下一个可用的网格单元格中

资源

本指南概述了网格布局规范的不同部分。要了解更多信息,请查看以下资源。