网格布局中的盒子对齐

CSS 网格布局实现了 Box Alignment Level 3 规范,它与 flexbox 用于在 flex 容器中对齐项目相同的标准。该规范详细说明了所有不同的布局方法中对齐方式的运作方式。布局方法将在可能的情况下符合规范,并根据其差异(功能和限制)实现个别行为。虽然该规范目前指定了所有布局方法的对齐细节,但浏览器尚未完全实现所有规范;但是,CSS 网格布局方法已被广泛采用。

本指南展示了网格布局中的盒子对齐方式的工作原理。您将在 flexbox 中看到这些属性和值的工作方式有很多相似之处。由于网格是二维的,而 flexbox 是一维的,因此您需要注意一些细微的差别。因此,我们将首先查看在网格中对齐事物时所涉及的两个轴。

网格布局的两个轴

在使用网格布局时,您可以使用两个轴来对齐事物 - **块轴** 和 **内联轴**。块轴是块在块布局中排列的轴。如果您的页面上有两个段落,它们一个在另一个下面显示,因此我们将其描述为块轴的方向。

Block axes are vertical.

**内联轴** 沿块轴运行,它是常规内联流中文本运行的方向。

Inline / row axis are horizontal.

我们能够在这两个轴上对齐网格区域内的内容以及网格轨道本身。

在块轴上对齐项目

The align-selfalign-items 属性控制块轴上的对齐。当我们使用这些属性时,我们正在更改项目在您放置它的网格区域中的对齐方式。

使用 align-items

在下面的示例中,我的网格中有四个网格区域。我可以使用网格容器上的 align-items 属性,使用以下值之一对齐项目

  • auto
  • normal
  • start
  • end
  • center
  • stretch
  • baseline
  • first baseline
  • last baseline
css
.wrapper {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 10px;
  grid-auto-rows: 100px;
  grid-template-areas:
    "a a a a b b b b"
    "a a a a b b b b"
    "c c c c d d d d"
    "c c c c d d d d";
  align-items: start;
}
.item1 {
  grid-area: a;
}
.item2 {
  grid-area: b;
}
.item3 {
  grid-area: c;
}
.item4 {
  grid-area: d;
}
html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
  <div class="item4">Item 4</div>
</div>

请记住,一旦设置了 align-items: start,每个子 <div> 的高度将由 <div> 的内容决定。这与完全省略 align-items 形成对比,在这种情况下,每个 <div> 的高度会拉伸以填充其网格区域。

The align-items 属性为所有子网格项目设置 align-self 属性。这意味着您可以使用网格项目上的 align-self 来单独设置该属性。

使用 align-self

在接下来的示例中,我将使用align-self属性来演示不同的对齐值。第一个区域展示了align-self的默认行为,即拉伸。第二个项目align-self值为start,第三个为end,第四个为center

css
.wrapper {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 10px;
  grid-auto-rows: 100px;
  grid-template-areas:
    "a a a a b b b b"
    "a a a a b b b b"
    "c c c c d d d d"
    "c c c c d d d d";
}
.item1 {
  grid-area: a;
}
.item2 {
  grid-area: b;
  align-self: start;
}
.item3 {
  grid-area: c;
  align-self: end;
}
.item4 {
  grid-area: d;
  align-self: center;
}
html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
  <div class="item4">Item 4</div>
</div>

具有内在长宽比的项目

规范中详细说明了align-self的默认行为是拉伸,但对于具有内在长宽比的项目除外,在这种情况下,它们的行为类似于start。这样做的原因是,如果将具有长宽比的项目设置为拉伸,则此默认设置会扭曲它们。

此行为现已在规范中得到澄清,但浏览器尚未实现正确的行为。在此之前,您可以确保项目不会拉伸(例如,作为网格直接子级的图像),方法是将align-selfjustify-self设置为start。这将模拟实现后的正确行为。

在内联轴上对齐项目

由于align-itemsalign-self处理块轴上项目的对齐方式,因此justify-itemsjustify-self在内联轴上执行相同的操作。您可以从中选择的 value 与align-self相同。

  • auto
  • normal
  • start
  • end
  • center
  • stretch
  • baseline
  • first baseline
  • last baseline

您可以在下面看到与align-items相同的示例。这次我们将应用justify-self属性。

再次,默认值为stretch,但对于具有内在长宽比的项目除外。这意味着默认情况下,网格项目将覆盖其网格区域,除非您通过设置对齐方式来更改它。示例中的第一个项目演示了这种默认对齐方式

css
.wrapper {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 10px;
  grid-auto-rows: 100px;
  grid-template-areas:
    "a a a a b b b b"
    "a a a a b b b b"
    "c c c c d d d d"
    "c c c c d d d d";
}
.item1 {
  grid-area: a;
}
.item2 {
  grid-area: b;
  justify-self: start;
}
.item3 {
  grid-area: c;
  justify-self: end;
}
.item4 {
  grid-area: d;
  justify-self: center;
}
html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
  <div class="item4">Item 4</div>
</div>

align-selfalign-items一样,您可以将justify-items应用于网格容器,以设置所有项目的justify-self值。

justify-selfjustify-items属性在 flexbox 中未实现。这是由于flexbox的单维性质,以及可能存在多个沿轴的项目,使得无法对单个项目进行对齐。要在 flexbox 中沿主内联轴对齐项目,请使用justify-content属性。

简写属性

place-items属性是align-itemsjustify-items的简写。

place-self属性是align-selfjustify-self的简写。

将项目居中于区域

通过组合对齐和对齐属性,我们可以轻松地将项目居中于网格区域内。

css
.wrapper {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
  grid-auto-rows: 200px;
  grid-template-areas:
    ". a a ."
    ". a a .";
}
.item1 {
  grid-area: a;
  align-self: center;
  justify-self: center;
}
html
<div class="wrapper">
  <div class="item1">Item 1</div>
</div>

在块轴上对齐网格轨道

如果您遇到网格轨道使用比网格容器更小的区域的情况,那么您可以将网格轨道本身对齐到该容器内。同样,它在块轴和内联轴上运行,align-content在块轴上对齐轨道,而justify-content在内联轴上执行对齐。place-content属性是align-contentjustify-content的简写。align-contentjustify-contentplace-content的 value 为

  • normal
  • start
  • end
  • center
  • stretch
  • space-around
  • space-between
  • space-evenly
  • baseline
  • first baseline
  • last baseline

在下面的示例中,我有一个 500 像素乘 500 像素的网格容器。我定义了 3 行和 3 列轨道,每个轨道 100 像素,间距为 10 像素。这意味着网格容器内在块方向和内联方向上都有空间。

align-content属性应用于网格容器,因为它在整个网格上工作。

默认对齐方式

网格布局中的默认行为是start,这就是为什么我们的网格轨道位于网格的左上角,与起始网格线对齐的原因

css
* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 100px);
  grid-template-rows: repeat(3, 100px);
  height: 500px;
  width: 500px;
  gap: 10px;
  grid-template-areas:
    "a a b"
    "a a b"
    "c d d";
}
.item1 {
  grid-area: a;
}
.item2 {
  grid-area: b;
}
.item3 {
  grid-area: c;
}
.item4 {
  grid-area: d;
}
html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
  <div class="item4">Item 4</div>
</div>

设置 align-content: end

如果我在容器中添加align-content,值为end,则所有轨道将移动到网格容器在块维度的结束线。

css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 100px);
  grid-template-rows: repeat(3, 100px);
  height: 500px;
  width: 500px;
  gap: 10px;
  grid-template-areas:
    "a a b"
    "a a b"
    "c d d";
  align-content: end;
}
.item1 {
  grid-area: a;
}
.item2 {
  grid-area: b;
}
.item3 {
  grid-area: c;
}
.item4 {
  grid-area: d;
}
html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
  <div class="item4">Item 4</div>
</div>

设置 align-content: space-between

我们还可以使用您可能从 flexbox 中熟悉的 value;space-betweenspace-aroundspace-evenly的空间分布 value。如果我们将align-content更新为space-between,您可以看到网格上的元素是如何间隔开的

css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 100px);
  grid-template-rows: repeat(3, 100px);
  height: 500px;
  width: 500px;
  gap: 10px;
  grid-template-areas:
    "a a b"
    "a a b"
    "c d d";
  align-content: space-between;
}
.item1 {
  grid-area: a;
}
.item2 {
  grid-area: b;
}
.item3 {
  grid-area: c;
}
.item4 {
  grid-area: d;
}
html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
  <div class="item4">Item 4</div>
</div>

值得注意的是,使用这些空间分布 value 可能会导致网格上的项目变得更大。如果一个项目跨越多个网格轨道,随着轨道之间添加更多空间,该项目需要变得更大以吸收空间。我们始终在严格的网格中工作。因此,如果您决定使用这些 value,请确保轨道的內容能够适应额外的空间,或者您已在项目上使用对齐属性,以使它们移动到起始位置而不是拉伸。

在下图中,我已经将网格放置在align-content值为start的位置,旁边是align-content值为space-between的网格。您可以看到项目 1 和 2 如何跨越两个行轨道,并获得了额外的高度,因为它们获得了添加到这两个轨道之间间隙的额外空间

Demonstrating how items become larger if we use space-between.

在内联轴上对齐网格轨道

在内联轴上,我们可以使用justify-content来执行与我们在块轴上使用align-content执行的对齐方式相同的类型。

使用相同的示例,我将justify-content设置为space-around。这再次导致跨越多个列轨道的轨道获得额外的空间

css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 100px);
  grid-template-rows: repeat(3, 100px);
  height: 500px;
  width: 500px;
  gap: 10px;
  grid-template-areas:
    "a a b"
    "a a b"
    "c d d";
  align-content: space-between;
  justify-content: space-around;
}
.item1 {
  grid-area: a;
}
.item2 {
  grid-area: b;
}
.item3 {
  grid-area: c;
}
.item4 {
  grid-area: d;
}
html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
  <div class="item4">Item 4</div>
</div>

对齐和自动边距

另一种在区域内对齐项目的方法是使用自动边距。如果您曾经通过将容器块的右和左边距设置为auto来将布局居中在视口中,那么您就知道自动边距会吸收所有可用空间。通过将两边的边距设置为auto,它会将块推到中间,因为两个边距都试图占用所有空间。

在接下来的示例中,我为项目 1 设置了auto的左边距。您可以看到內容现在如何被推到区域的右侧,因为自动边距在分配了该项目內容的空间后会占用剩余空间

css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 100px);
  grid-template-rows: repeat(3, 100px);
  height: 500px;
  width: 500px;
  gap: 10px;
  grid-template-areas:
    "a a b"
    "a a b"
    "c d d";
}
.item1 {
  grid-area: a;
  margin-left: auto;
}
.item2 {
  grid-area: b;
}
.item3 {
  grid-area: c;
}
.item4 {
  grid-area: d;
}
html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
  <div class="item4">Item 4</div>
</div>

您可以使用Firefox 网格高亮显示查看项目是如何对齐的

Image showing auto-margins using the grid highlighter.

对齐和书写模式

在所有这些示例中,我一直都在使用英语,这是一种从左到右的语言。这意味着当我们用物理方向思考时,我们的起始线位于网格的顶部和左侧。

CSS 网格布局和盒子对齐规范旨在与 CSS 中的书写模式配合使用。这意味着如果您正在使用阿拉伯语等从右到左的语言,则网格的起始位置将是顶部和右侧,因此justify-content: start的默认设置将是网格轨道从网格的右侧开始。

然而,设置自动边距、使用margin-rightmargin-left,或者使用toprightbottomleft偏移量绝对定位项目不会遵守书写模式。在下一份指南中,我们将进一步探讨 CSS 网格布局、盒子对齐和书写模式之间的这种交互。如果您开发的网站随后将在多种语言中显示,或者您想在设计中混合语言或书写模式,那么了解这一点很重要。