使用基于行的布局的网格布局

介绍网格布局基本概念的文章中,我们开始了解如何使用行号在网格上定位项目。在本文中,我们将全面探讨规范中这个基本功能的工作原理。

从使用编号行开始你的网格探索是最合乎逻辑的,因为当你使用网格布局时,你总是拥有编号行。这些行是为列和行编号的,并从 1 开始索引。请注意,网格是根据文档的书写模式索引的。在英语等从左到右的语言中,第 1 行位于网格的左侧。如果你正在使用阿拉伯语等从右到左的语言,那么第 1 行将位于网格的最右侧。我们将在以后的指南中详细了解书写模式和网格之间的交互作用。

基本示例

作为一个非常简单的例子,我们可以拿一个具有 3 列轨道和 3 行轨道的网格。这让我们在每个维度上有 4 行。

在我们的网格容器内,我们有四个子元素。如果我们不以任何方式将它们放置到网格上,它们将根据自动放置规则进行布局,每个单元格中放置一个项目。如果你使用Firefox 网格高亮器,你就可以看到网格是如何定义列和行的。

Our grid highlighted in DevTools

css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 100px);
}
html
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
</div>

按行号定位项目

我们可以使用基于行的放置来控制这些项目在网格上的位置。我们希望第一个项目从网格的最左侧开始,并跨越一个单列轨道。它也应该从第一行开始,位于网格的顶部,并跨越到第四行。

css
.box1 {
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 1;
  grid-row-end: 4;
}

当你放置一些项目时,网格上的其他项目将继续使用自动放置规则进行布局。我们将在以后的指南中仔细研究它们是如何工作的,但你可以看到,当你工作时,网格将未放置的项目布局到网格的空单元格中。

通过分别处理每个项目,我们可以放置所有四个跨越行和列轨道的项目。请注意,如果我们希望可以留下空单元格。网格布局非常棒的一点是,它能够在我们的设计中留出空白,而无需使用边距将项目推开,以防止浮动项目上升到我们留下的空白区域。

html
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
</div>
css
.box1 {
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 1;
  grid-row-end: 4;
}
.box2 {
  grid-column-start: 3;
  grid-column-end: 4;
  grid-row-start: 1;
  grid-row-end: 3;
}
.box3 {
  grid-column-start: 2;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: 2;
}
.box4 {
  grid-column-start: 2;
  grid-column-end: 4;
  grid-row-start: 3;
  grid-row-end: 4;
}

grid-columngrid-row 简写

我们在这里有相当多的代码来放置每个项目。毫不奇怪,有一个简写形式grid-column-startgrid-column-end 属性可以组合到 grid-column 中,grid-row-startgrid-row-end 可以组合到 grid-row 中。

html
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
</div>
css
.box1 {
  grid-column: 1 / 2;
  grid-row: 1 / 4;
}
.box2 {
  grid-column: 3 / 4;
  grid-row: 1 / 3;
}
.box3 {
  grid-column: 2 / 3;
  grid-row: 1 / 2;
}
.box4 {
  grid-column: 2 / 4;
  grid-row: 3 / 4;
}

默认跨度

在上面的示例中,我们指定了每个结束行和列行,以便演示属性,但在实践中,如果项目只跨越一个轨道,你可以省略 grid-column-endgrid-row-end 值。网格默认跨越一个轨道。

使用长手放置时的默认跨度

这意味着我们的初始长手示例将如下所示

html
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
</div>
css
.box1 {
  grid-column-start: 1;
  grid-row-start: 1;
  grid-row-end: 4;
}
.box2 {
  grid-column-start: 3;
  grid-row-start: 1;
  grid-row-end: 3;
}
.box3 {
  grid-column-start: 2;
  grid-row-start: 1;
}
.box4 {
  grid-column-start: 2;
  grid-column-end: 4;
  grid-row-start: 3;
}

使用简写放置时的默认跨度

我们的简写形式将如下面的代码所示,没有正斜杠,并且没有第二个值为仅跨越一个轨道的项目。

html
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
</div>
css
.box1 {
  grid-column: 1;
  grid-row: 1 / 4;
}
.box2 {
  grid-column: 3;
  grid-row: 1 / 3;
}
.box3 {
  grid-column: 2;
  grid-row: 1;
}
.box4 {
  grid-column: 2 / 4;
  grid-row: 3;
}

grid-area 属性

我们可以更进一步,使用单个属性 grid-area 来定义每个区域。grid-area 的值顺序如下。

  • grid-row-start
  • grid-column-start
  • grid-row-end
  • grid-column-end
html
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
</div>
css
.box1 {
  grid-area: 1 / 1 / 4 / 2;
}
.box2 {
  grid-area: 1 / 3 / 3 / 4;
}
.box3 {
  grid-area: 1 / 2 / 2 / 3;
}
.box4 {
  grid-area: 3 / 2 / 4 / 4;
}

grid-area 的值顺序可能看起来有点奇怪,它与我们指定边距和填充等简写形式的方向相反。可能有助于意识到这是因为网格使用 CSS 书写模式规范中定义的流相关方向。我们将在以后的文章中探讨网格如何与书写模式一起工作,但我们有四个流相关方向的概念

  • block-start
  • block-end
  • inline-start
  • inline-end

我们使用英语,一种从左到右的语言。我们的块开始是网格容器的顶行线,块结束是容器的最后一行线。我们的内联开始是左边的列线,因为内联开始始终是文本在当前书写模式下开始书写的位置,内联结束是我们网格的最后一列线。

当我们使用grid-area属性指定网格区域时,我们首先定义两个开始线block-startinline-start,然后定义两个结束线block-endinline-end。这乍一看似乎很不寻常,因为我们习惯了顶部、右侧、底部和左侧的物理属性,但如果你开始将网站视为书写模式的多方向性,就会更有意义。

倒数

我们也可以从网格的块和内联结束处倒数,对于英语来说,那是右边的列线和最后一行线。这些线可以被视为-1,你可以从那里倒数——因此倒数第二行是-2。值得注意的是,最后一行是显式网格的最后一行,即由grid-template-columnsgrid-template-rows定义的网格,并且不考虑在该网格之外隐式网格中添加的任何行或列。

在下一个示例中,我们在放置项目时从网格的右侧和底部开始,翻转了我们正在使用的布局。

html
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
</div>
css
.box1 {
  grid-column-start: -1;
  grid-column-end: -2;
  grid-row-start: -1;
  grid-row-end: -4;
}
.box2 {
  grid-column-start: -3;
  grid-column-end: -4;
  grid-row-start: -1;
  grid-row-end: -3;
}
.box3 {
  grid-column-start: -2;
  grid-column-end: -3;
  grid-row-start: -1;
  grid-row-end: -2;
}
.box4 {
  grid-column-start: -2;
  grid-column-end: -4;
  grid-row-start: -3;
  grid-row-end: -4;
}

将项目跨越网格拉伸

能够解决网格的开始和结束线很有用,因为你可以使用以下方法将项目跨越整个网格拉伸

css
.item {
  grid-column: 1 / -1;
}

间隙或巷道

CSS 网格规范包括使用 column-gaprow-gap 属性在列和行轨道之间添加间距的能力。它们指定了一个间距,其行为类似于多列布局中的 column-gap 属性。

注意:当网格第一次在浏览器中发布时,column-gaprow-gapgap 属性带有grid-前缀,分别为grid-column-gapgrid-row-gapgrid-gap

浏览器正在更新其渲染引擎以删除此前缀,但是有前缀的版本将被保留为别名,使其安全使用。

间距只出现在网格轨道之间,它们不会在容器的顶部和底部、左侧或右侧添加空间。我们可以通过在网格容器上使用这些属性,将间距添加到我们之前的示例中。

html
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
</div>
css
.box1 {
  grid-column: 1;
  grid-row: 1 / 4;
}
.box2 {
  grid-column: 3;
  grid-row: 1 / 3;
}
.box3 {
  grid-column: 2;
  grid-row: 1;
}
.box4 {
  grid-column: 2 / 4;
  grid-row: 3;
}
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 100px);
  column-gap: 20px;
  row-gap: 1em;
}

间距速记

这两个属性也可以用速记 gap 表示。如果只为gap提供一个值,它将应用于列和行间距。如果指定两个值,第一个用于row-gap,第二个用于column-gap

css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 100px);
  gap: 1em 20px;
}

就项目的基于线的定位而言,间距的作用就像线获得了额外的宽度一样。从该线开始的任何内容都将在间距之后开始,你无法解决间距或将任何内容放置到其中。如果你想要更像常规轨道一样起作用的间距,当然可以定义一个轨道来专门用于此目的。

使用 span 关键字

除了通过数字指定开始和结束线之外,你还可以指定一个开始线,然后指定你希望区域跨越的轨道数。

html
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
</div>
css
.box1 {
  grid-column: 1;
  grid-row: 1 / span 3;
}
.box2 {
  grid-column: 3;
  grid-row: 1 / span 2;
}
.box3 {
  grid-column: 2;
  grid-row: 1;
}
.box4 {
  grid-column: 2 / span 2;
  grid-row: 3;
}

你也可以在grid-row-start/grid-row-endgrid-column-start/grid-column-end的值中使用span关键字。以下两个示例将创建相同的网格区域。在第一个示例中,我们设置开始行线,然后设置结束线,我们指定希望区域覆盖 3 个轨道。区域将从第 1 行开始,从第 1 行结束 3 行;也就是说,区域将在第 4 行结束。

css
.box1 {
  grid-column-start: 1;
  grid-row-start: 1;
  grid-row-end: span 3;
}

在第二个示例中,我们指定我们希望项目结束的结束行线,然后将开始行线设置为span 3。这意味着项目需要从指定的行线向上跨越。区域将从第 4 行开始,跨越 3 行到第 1 行。

css
.box1 {
  grid-column-start: 1;
  grid-row-start: span 3;
  grid-row-end: 4;
}

要熟悉基于线的网格定位,请尝试通过将项目放置在具有不同列数的网格上,构建一些常见的布局。请记住,如果你没有放置所有项目,任何剩余的项目将根据自动放置规则放置。这可能会导致你想要的布局,但如果某个东西出现在了意料之外的地方,请检查是否已为它设置了位置。

此外,请记住,当你在网格上显式放置项目时,这些项目可以相互重叠。这可能会产生一些不错的效果,但是如果你指定了错误的开始或结束线,你也会最终导致项目重叠错误。 Firefox 网格高亮器 在你学习时非常有用,尤其是当你的网格很复杂时。