Web 基础知识:网格

594 阅读8分钟

本文是系列文章的一部分:Web 基础知识

这个 CSS 属性display: grid通常被称为 gridbox。与 flexbox 不同,它能够使用相交的列和行来创建二维布局。

今天我们将学习如何使用网格的功能来构建适应用户需求的动态布局。

网格大小

网格和网格单元接受数值。这些数值可以是相对于父级尺寸的值、在整个网格中重复的固定尺寸,或者相对于其元素尺寸的尺寸!

行为
px为每一列设置静态大小。
fr根据容器大小或内容大小(如果未设置容器大小)设置一个分数值。这将考虑该gap属性,并确保内容不会溢出。 仅在 内可用display: grid
%根据容器大小设置百分比值。与 不同fr,此方法将忽略gap属性,如果百分比和 的总和gap大于 100%,内容将溢出。
vwvh根据视口大小设置百分比值。与 不同fr,这将忽略gap属性,并且如果百分比和 的总和gap大于 100%,内容将溢出。

现在让我们看看我们将要使用的属性。

模板

区域

要定义网格将包含多少个区域,grid-template-areas需要传入任意一个项来指定布局槽位。项的数量决定了特定布局可以占用的“槽位”数量。

这里我们创建一个 3x3 的布局。 每个布局的分布如下:

grid-template-areas:  "a a a"  "b b c"  "b b c";

为了更好地说明这一点,让我们将术语从字母更改为实际内容并使用真实的 CSS:

.grid-container {  
    grid-template-areas:  "heading heading heading"    
                          "content content sidebar"    
                          "content content sidebar";  
    gap: 16px;  height: 376px;
}
  • 占据整个顶行的标题。
  • 内容占据了剩余网格空间的 2/3。我们稍后会讨论这个问题。
自定义区域复制链接

使用grid-template-areas将定义默认分布,但这并不意味着它不能被自定义。使用columnrow命令,我们可以调整每个模板区域的显示方式。

默认情况下,列和行均匀分布。

grid-template-areas:  "a a"  "b c";

网格顶部有一个项目,横跨两列,底部有两个项目

然而,有一个警告:它们的大小也取决于内容。

现在让我们逐一看一下。

列复

如果内容超出了列的常规大小,该列将会扩展以容纳内容。这意味着为了强制分配,我们必须调用另一个属性,称为grid-template-columns

grid-template-columns属性接受一个数值。它可以是相对于父级尺寸的值,也可以是在整个网格中重复的固定尺寸,或者相对于其元素尺寸的尺寸!

让我们看一个例子,我们覆盖了列的值,使grid-template-areasgrid-template-columns相互对立。在这个演示中,尽管内容根据区域占用了更多空间,但列覆盖却使其占用的空间减少了。

如果内容超出了行的常规大小,该行将会增长以容纳内容。这意味着为了强制分配,我们必须调用另一个属性,称为grid-template-rows

grid-template-rows属性接受一个数值。它可以是相对于父级尺寸的值,也可以是在整个网格中重复的固定尺寸,或者相对于其元素尺寸的尺寸!

grid-template-rows: 1fr 2fr 1fr;

具有单列和三个项目的网格;中间项目的高度是其上下另外两个项目高度的两倍

间隙

gap属性的含义不言自明。它是一个简写属性,用于定义网格单元之间的间距。它接受两个我们已经讨论过的任意数值作为输入,例如百分比、分数、视口单位等等。

.grid-container {  display: grid;  gap: 24px 16px; }

了解更多

📚 MDN:gap


自动属性

流动

默认情况下,grid-auto-flow将元素的顺序设置为row,这意味着项目将按行排序,直到填满,然后它们将继续换行到下一个。

.grid-container {  display: grid;}

元素从一行流向另一行的网格。

您可以将grid-auto-flow属性设置为column。在这种情况下,项目将垂直放置,然后在一列填满后换行到下一列。

元素从一列流向另一列的网格。

列和行

有时,物品可能会超出网格的大小,或者您可能想要创建一个不可见的网格系统来放置物品。

在这些情况下,您可以指定自动生成的单元格的大小。

.grid-container {    
    display: grid;  grid-auto-flow: column;  gap: 16px;    
    grid-template-rows: 48px 48px;  grid-template-columns: 72px 72px;  
    grid-auto-columns: 128px;  grid-auto-columns: 100px;                        }
.fifth-item { grid-column: 5;  grid-row: 2;}

显示网格自动项目的网格。

实时代码示例:Gridbox 布局

结盟

添加display: grid到容器中会导致其所有直接后代成为网格项。与**flexbox**类似,我们可以使用放置方法来帮助容器内的网格项对齐、两端对齐和间距调整。

使用place-items

align-items放置物品分别是和的简写justify-items

place-items: start end;
align-items: start;
justify-items: end;

现在让我们看看它的实际效果。

place-items: center center;

垂直和水平居中的项目网格。

place-items: center end;

项目网格垂直居中,但与右角对齐。

place-items: end end;

与右下角对齐的项目网格。

place-items: start start;

与右上角对齐的项目网格。

place-items: start center;

项目网格水平居中并与顶部边缘对齐。

子网格

Subgrid 是一个强大的功能,可以回答以下问题:

  • 如果我想让网格项的子元素也与网格对齐怎么办?
  • 如果我想确保某些元素无论内容如何都沿轴对齐,该怎么办?

甚至:

  • 如果我想为特定的一组网格单元设置样式该怎么办?

Subgrid 对于所有这些用例来说都非常棒。

理论上,子网格非常简单。要创建子网格项,我们必须应用以下属性:

.subgrid-container {  
    grid-template-columns: subgrid;  
    grid-template-rows: subgrid; 
}

然后,我们可以在任何子布局中设置与网格项相同的属性:

.subgrid-item {  grid-area: }

这将导致该布局附加到父级网格单元。一切如您所愿!


使用子网格

让我们以自己的网站为例来学习一下吧!

在我们的主页上,我们有一个卡片网格。在这些卡片中,我们有一个包含标签的容器。

让我们尽可能地重建布局,使用弹性布局和堆叠容器;您知道,这是通常的做法。

两张卡片分别包含标题、描述和下方的一组标签。由于文本长度不同,它们未对齐。

这与设计非常接近,但有一点不同:标签容器的位置。

与之前相同的两张卡片,但颜色变暗,突出显示了标签容器的错位。

在我们的设计中,我们有意将其与卡片底部对齐,以便为内容的分发提供一个锚点。

我们可以使用subgridgrid-template-areas来确保它们正确对齐!

.grid-container {  
    width: clamp(640px, 100vw, 960px); display: grid;   
    grid-template-areas: "content content"       "tags tags";  
    grid-template-columns: 1fr 1fr;  gap: 0px 32px;  
    padding: 32px;  background-color: #E5F2FF;  box-sizing: border-box;
}

这样我们就得到了更新后的网格:

和之前一样的两张卡片,看似没有更新。但实际上,网格线已经变了。

但是等等...看起来一样。

确实如此!如果没有子元素使用grid-area,并且没有设置绘制单元格的尺寸,那么网格单元格就会直接折叠成空白。

虽然看起来可能不像,但我们的布局中有两行,但我们需要附加内容来填充它们!

重构我们的布局

在我们上面的演示中,我们的文章卡片中的每个项目都是松散地放在弹性外容器内的。

为了正确调整我们的布局,我们现在将文章卡的内容分成两种布局:content-containertag-container

<div class="grid-container">  <div class="article">    <div class="content-container">      <h2>Web Fundamentals: HTML</h2>      <p>The first chapter of this series offers an introductory dive into the box model, HTML defaults and semantic elements.</p>    </div>    <div class="tag-container">      <div class="tag">css</div>      <div class="tag">html</div>      <div class="tag">design</div>    </div>  </div>  <div class="article">    <div class="content-container">      <h2>Entity Component System: The Perfect Solution to Reusable Code?</h2>      <p>The ECS pattern is used by many game engines to create stateless, reusable game logic. But how does it work?</p>    </div>    <div class="tag-container">      <div class="tag">rust</div>      <div class="tag">computer science</div>      <div class="tag">opinion</div>    </div>  </div></div>

我们刚才所做的就是将其tag-container与布局的其余部分分开,以便它可以与tags模板行绑定。

.article {    display: grid;   grid-template-columns: subgrid;  grid-template-rows: subgrid;   grid-row: content / tags;   padding: 24px;  border: 8px solid rgba(135, 206, 255, 0.32);  border-radius: 32px;  box-sizing: border-box;}
.content-container {    grid-area: content;  display: flex;  flex-direction: column;  height: fit-content;  gap: 8px;  padding-bottom: 16px;}
.tag-container {    grid-area: tags;  display: flex;  flex-wrap: wrap;  height: fit-content;  gap: 8px;}

与之前相同的两张卡片,但现在重构以正确对齐其网格区域。

这样,我们就成功对齐了我们的标签!

即使标签溢出到另一行,它们也会保持对齐!下面的演示展示了视口调整大小时的这种行为。

为什么要使用 CSS 网格?

CSS 网格如此受欢迎是有原因的!它的主要优点如下:

  1. 能够创建需要列和行的复杂布局
  2. 提供最简单、最快捷的居中元素方法
  3. 详细而强大,具有大量自定义选项

下一步:响应式设计

现在我们都熟悉了 Flexbox 和 Grid,是时候通过构建用户可以在任何外形尺寸上享受的响应式布局来对它们进行测试了。

这就是下一章的内容。跟我来!