满足大多数布局需求的 4 个 CSS 网格属性(以及一个值)

Avatar of Anna Prenzel
Anna Prenzel

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 价值 200 美元的免费积分!

CSS 网格为我们提供了强大的网站布局系统。 CSS-Tricks 指南 为您全面概述了网格属性及其布局示例。 我们将在这里采用一种逆向方法,向您展示满足大多数布局需求所需的最小的网格属性集。

这五个属性将助您快速入门

  • display(用于 grid 值)
  • grid-template-columns
  • grid-gap
  • grid-auto-flow
  • grid-column / grid-row

这真的很简单。 假设您想为小型、中型和大型屏幕实现以下布局。

小型和中型屏幕
大型屏幕布局

这是我们将要使用的标记


<!-- Stuff before -->

<nav class="container-nav">
  <ul>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
  </ul>
</nav>

<div class="container-main">
  <section class="item item-type-a"></section>
  <section class="item item-type-b"></section>
  <section class="item item-type-b"></section>
  <section class="item container-inner">
    <section class="item-inner"></section>
    <section class="item-inner"></section>
    <section class="item-inner"></section>
    <section class="item-inner"></section>
    <section class="item-inner"></section>
  </section>
</div>

<!-- Stuff after -->

如果我们应用一些基本样式,就会得到以下结果,这对于小型屏幕来说已经足够了

现在我们可以开始使用网格属性了!

使用 display: grid 将页面划分为独立的布局容器

首先,我们需要确定页面中哪些部分应该与网格布局对齐。 可以为整个页面定义单个网格布局。 但是,对于结构非常复杂的网站(例如新闻网站),处理大型网格很快就会变得难以驾驭。 在这种情况下,我建议将页面分解成几个独立的网格容器。

像这样

您如何在什么应该是什么不应该成为网格之间划清界限? 这里有一个我遵循的个人经验法则

如果页面特定部分的布局不适合相邻或周围部分的网格,则将该部分设置为自己的网格容器。

我在以下图片中用网格线绘制了带有类 .container-main 的页面部分。 您可能会注意到,标记中的带有 .container-inner 类的部分不完全适合网格行。

这是一个可能的布局,其中如果选择更细的线栅格,则小部分将适合周围的网格。 在这里,单独的网格容器不是绝对必要的。

要开始,让我们将 .container-main 设置为网格容器。 这是 CSS 网格的基本构建块 - 使用 display 属性将元素转换为网格容器

.container-main {
  display: grid;         
}

我们也希望对其他网格容器执行相同的操作

.container-inner {
  display: grid;         
}

.container-nav {
  display: grid;         
}

使用 grid-template-columns 定义所需的列

接下来,我们将定义每个网格容器中所需的列数以及这些列的宽度。 我对列数的准则: 使用不同屏幕尺寸所需的最大列数的最小公倍数。

它是如何工作的? .container-main 元素在中型屏幕上总共有两列。 如果我们将其乘以大型屏幕上的列数(三列),我们将得到总共六列。

我们可以对导航 .container-inner 元素执行相同的操作。 在中型屏幕上,有三个列,我们将其乘以大型屏幕上的一个列,得到总共三个列。

.container-nav 元素没有提供任何列数。 在这种情况下,网格系统应自动将列数调整为菜单元素的数量。 通常会在导航中添加或删除项目,如果它能相应地做出响应将非常好,这是网格稍后可以帮助我们实现的功能。

好的,因此我们为每个网格容器定义了列数。 让我们使用 grid-template-columns 属性将它们设置到位。 但是,首先要考虑几个细节

  • grid-template-columns 属性仅在网格容器上使用。 换句话说,您不会在容器内的网格项上找到它(至少不会使用正确的方式)。
  • 该属性接受许多不同的值,这些值同时定义了列数及其宽度。 我们这里感兴趣的是分数 (fr) 单位。 我强烈建议查看 Robin 的概述,因为它在网格中是独一无二的,并且在确定网格元素如何适合网格容器方面做得非常出色。

我们需要在 .container-main 中创建六个等宽列。 我们可以这样写

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

或者,我们可以转向 repeat() 函数将其简化为更易读的内容

.container-main {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
}

让我们利用这些知识也应用于 .container-inner 元素,我们决定它需要三列。

.container-inner {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

使用 grid-gap 在网格项之间添加间距

默认情况下,网格会使用网格容器中的所有空间来容纳网格项。 使元素紧密相邻可能是设计要求,但不适用于我们正在制作的特定布局。 我们希望在元素之间留出一些空间!

我们有 grid-gap 属性来实现这一点。 同样,这只是一个网格容器的属性,它的作用是在网格项之间创建垂直和水平间距。 它实际上是一个简写属性,它结合了 grid-row-gap 的垂直间距功能和 grid-column-gap 的水平间距功能。 能够将它们分解成这样很方便,但在像这样我们在每个方向上都使用相同间距的情况下,简写 grid-gap 编写起来更方便。

我们希望在 .container-main 中的网格项之间留出 20px 的空间,在 .container-inner 中留出 10px 的空间,在 .container-nav 中留出 5px 的空间。 没问题! 只需在每个网格容器上添加一行代码即可。

.container-main{
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  grid-gap: 20px;
}

.container-inner {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 10px;
}

.container-nav {
  display: grid;
  grid-gap: 5px;
}

使用 grid-column 和 grid-row 确定单个网格项的大小

现在是时候将布局塑造成我们想要的样子了!

首先是 grid-column 属性,它允许我们将网格项扩展到 n 列,其中 n 是要跨越的列数。 如果您认为这听起来非常类似于 rowspan 属性,它允许我们将单元格扩展到 HTML 表格中的多行,那么您是对的。

当我们在 .container-main 元素中的网格 .item 上使用它时,以及在 .container-inner 中的 .inner-item 元素上使用它时,它看起来像这样

.item {
  grid-column: span 6;
}

.item-inner {
  grid-column: span 3;
}

我们在这里表示,每个项目在我们主容器中跨越六行,在我们内部容器中跨越三行 - 这相当于每个容器中的总列数。

CSS 网格的一个有趣之处在于,我们能够对网格线进行命名它们自带隐式名称,但为它们命名是一种强大的方法,可以区分每个列上的轨道上的起始线和结束线。

我们可以在不同的断点更改项目应跨越的列数和行数

@media screen and (min-width: 600px) {
  .item-type-b {
    grid-column: span 3;
  }

  .item-inner {
    grid-column: span 1;
  }
}

@media screen and (min-width: 900px) {
  .item {
    grid-column: span 2;
    grid-row: span 2;
  }

  .item-type-b{
    grid-row: span 1;
  }

  .item-inner{
    grid-column: span 3;
  }
}

使用 grid-auto-flow 控制元素的放置

CSS 网格会按顺序将元素放置在一行一行中。 这就是为什么我们示例中的结果目前看起来像这样

可以通过将 grid-auto-flow 属性设置为列 (row 是默认值) 来实现逐列放置。 我们的布局将在两种情况下受益于按列放置。 首先,它使我们的菜单项最终以水平方向显示。 其次,它将容器类元素带入所需的组合中。

最终结果

结论:多少规范?

网格系统允许我们在“尽可能少地制定必要规范”的口号下工作。为了仅展示构建复杂布局所需的知识量很少,我们只介绍了将元素转换为 CSS 网格容器以及将其中元素转换为网格项目的必要规范中的几个。

CSS 网格支持更多用例,例如:

  • 我们希望制定更少的规范,以便更多地依赖自动定位。
  • 我们希望制定更多规范,以便确定结果布局的更多细节。

如果第一个案例适用,那么值得考虑以下附加网格选项:

  • 使用 `grid-template-columns` 创建网格时,您可以使用 `auto` 关键字让网格系统自动确定各个列的宽度,或者使用 `min-content`、`max-content` 或 `fit-content` 设置使其适应现有内容。
  • 您可以借助 `repeat`、`auto-fill`、`auto-fit` 和 `minmax` 让网格系统自动确定所需列数。甚至媒体查询也可以变得冗余,这些工具有助于在不添加更多媒体查询的情况下使布局灵活。

以下是我推荐的一些关于此主题的文章:成为 CSS 网格忍者!CSS 网格中的自动调整列宽:auto-fill vs. auto-fit.

如果第二个案例适用,CSS 网格为您提供了更多设置选项:

  • 您可以使用 `grid-template-columns` 属性显式指定列的宽度,以您选择的单位(例如 `px` 或 `%`)。此外,还可以使用 `grid-template-rows` 属性来定义行数和宽度,如果存在特定行数的话。
  • 您还可以为 `grid-column` 和 `grid-row` 定义特定列或行号作为定位值(或者使用 `grid-column-start`、`grid-column-end`、`grid-row-start` 或 `grid-row-end` 属性)。

我们甚至还没有谈到 CSS 网格对齐!不过,即使没有触及该主题,我们也能实现如此多的功能,这表明 CSS 网格功能多么强大。