CSS 网格 - 表格布局恢复正常。立足于正方形

Surma
Surma

要点

如果您熟悉 Flexbox,就会对 Grid 感到熟悉。 Rachel Andrew 维护着一个专门介绍 CSS 网格的网站,可帮助您入门。网格功能现在可在 Google Chrome 中使用。

Flexbox?网格?

在过去的几年里,CSS Flexbox 得到广泛使用,浏览器支持也看起来非常不错(除非您是不得不支持 IE9 及更低版本的人之一)。Flexbox 简化了许多复杂的布局任务,例如元素之间的等距间距、自上而下的布局或 CSS 专长:垂直居中。

无法跨多个 Flexbox 容器对齐元素。

但唉,屏幕通常还有一个我们需要关注的第二个维度。 如果没有自行调整元素的大小,很遗憾,仅使用 Flexbox 无法同时达到垂直和水平的节奏。这就是 CSS 网格的用武之地。

CSS 网格已经处于开发阶段,在大多数浏览器中,一个标志背后的时间已超过 5 年。为了避免像 Flexbox 那样存在错误的发布,我们还花了额外的时间来提升互操作性。因此,如果您在 Chrome 中使用 Grid 实现布局,则有可能在 Firefox 和 Safari 中得到相同的结果。在撰写本文时,Microsoft Edge 的 Grid 实现已过时(与 IE11 中已有的实现相同),并且更新处于“考虑中”状态。

尽管 Flexbox 和 Grid 在概念和语法上很相似,但请不要将 Flexbox 和 Grid 视为互相竞争的布局技术。网格以两种尺寸排列,而 Flexbox 则会以一维布局排列。两者结合使用可产生协同效应。

定义网格

为了熟悉 Grid 的各个属性,我强烈建议大家参阅 Rachel Andrew 的 Grid By Example 或 CSS Tricks 的备忘单。如果您熟悉 Flexbox,就会熟悉很多属性及其含义。

我们来看一个标准的 12 列网格布局。传统的 12 列布局很受欢迎,因为数字 12 可以被 2、3、4 和 6 整除,因此在许多设计中很有用。我们来实现此布局:

无法跨多个 Flexbox 容器对齐元素。

我们先从标记代码开始:

<!DOCTYPE html>
<body>
    <header></header>
    <nav></nav>
    <main></main>
    <footer></footer>
</body>

在样式表中,我们首先展开 body,使其覆盖整个视口,并将其转换为网格容器

html, body {
    width: 100vw;
    min-height: 100vh;
    margin: 0;
    padding: 0;
}
body {
    display: grid;
}

现在我们使用 CSS 网格太棒了!

下一步是实现网格的行和列。我们可以在模型中实现所有 12 列,但由于我们并未使用每一列,因此这样做会使 CSS 变得不必要的杂乱。为简单起见,我们将通过以下方式实现布局:

简化布局示例

页眉和页脚的宽度可变,内容在这两个尺寸上都是可变的。导航栏的两个尺寸也是可变的,但我们对其施加的最小宽度为 200px。(为什么?当然,要展示 CSS 网格的功能)

在 CSS 网格中,这组列和行称为轨道。我们先来定义第一组轨道,即行:

body {
    display: grid;
    grid-template-rows: 150px auto 100px;
}

grid-template-rows 采用一系列定义各行的大小。在本例中,我们为第一行指定 150 像素的高度,为最后一行指定 100 像素的高度。中间行设置为 auto,这意味着它会调整到必要的高度,以容纳该行中的网格项(网格容器的子项)。由于正文将在整个视口上拉伸,因此包含相应内容的轨道(上图中以黄色图标标示)至少会填满所有可用空间,但如果需要,它会扩大(并使文档滚动)。

对于列,我们希望采用更具动态性的方法:我们希望导航和内容都能放大(和缩小),但我们希望导航始终不会缩小到 200px 以下,并且希望内容大于导航。在 Flexbox 中,我们会使用 flex-grow 和 flex-shrink,但在 Grid 中,则略有不同:

body {
    display: grid;
    grid-template-rows: 150px auto 100px;
    grid-template-columns: minmax(200px, 3fr) 9fr;
}

我们要定义 2 列。第一列使用 minmax() 函数定义,该函数接受 2 个值:该������的���小���������大小。(就像 min-widthmax-width 合二为一。)正如我们之前讨论的那样,最小宽度为 200 像素。宽度上限为 3frfr 是特定于网格的单元,可让您向网格元素分配可用空间。fr 可能代表“fraction unit”,但也可能很快表示免费单元。此处的值表示这两列都将放大以填充屏幕,但内容列的宽度始终是导航列的 3 倍(前提是导航列的宽度始终大于 200px)。

虽然网格项的放置位置尚不正确,但行和列的 size 行为正确,可以产生我们想要的行为:

放置商品

Grid 最强大的功能之一是能够在不考虑 DOM 顺序的情况下放置项。(不过,由于屏幕阅读器会在 DOM 中进行导航,因此我们强烈建议您注意如何对元素重新排序,以便能够正常访问该文件。)如果未手动放置,这些元素将按 DOM 顺序排列在网格中,从左到右、从上到下排列。每个元素占用一个单元格。可以使用 grid-auto-flow 更改网格的填充顺序。

那么,我们如何放置元素呢?可以说,放置网格项的最简单方法是定义它们要覆盖的列和行。Grid 提供了两种语法来实现这一点:在第一种语法中,您定义起点和终点。在第二个示例中,您定义起点和跨度:

header {
    grid-column: 1 / 3;
}
nav {
    grid-row: 2 / span 2;
}
手动设置展示位置

我们希望标题从第一列开始,并在第三列之前结束。 导航应从第��行开始,总共跨越 2 行。

从技术层面来说,我们已经完成了布局的实现,但我想向大家展示一些 Grid 提供的便捷功能,以便您更轻松地进行放置。第一个功能是为轨道边界命名,并用这些名称作为放置位置:

body {
    display: grid;
    grid-template-rows: 150px [nav-start] auto 100px [nav-end];
    grid-template-columns: [header-start] minmax(200px, 3fr) 9fr [header-end];
}
header {
    grid-column: header-start / header-end;
}
nav {
    grid-row: nav-start / nav-end;
}

上面的代码将产生与之前代码相同的布局。

更强大的功能是为网格中的整个区域命名:

body {
    display: grid;
    grid-template-rows: 150px auto 100px;
    grid-template-columns: minmax(200px, 3fr) 9fr;
    grid-template-areas: "header header"
                        "nav    content"
                        "nav    footer";
}
header {
    grid-area: header;
}
nav {
    grid-area: nav;
}

grid-template-areas 接受一串以空格分隔的名称,以便开发者为每个单元格命名。如果两个相邻的单元格名称相同,则它们将合并至同一区域。这样,您就可以为布局代码提供更多语义,并让媒体查询更直观。同样,此代码会生成与之前相同的布局。

还有其他问题吗?

是的,确实有太多内容,一篇博文要介绍。 Rachel Andrew 也是一名 GDE,是 CSS 工作组的特邀专家,从一开始就与他们合作,以确保 Grid 简化网页设计。她甚至还在上面写了一本。她的网站 Grid By Example 提供了熟悉 Grid 的实用资源。许多人认为 Grid 是网页设计的革命性步骤,现在 Chrome 中默认启用该功能,因此您可以立即开始使用。