Dark Dwarf Blog background

Grid

Grid

1. Grid 概述

CSS Grid 布局是一个强大的二维 (2D) 布局系统,意味着它可以同时处理行和列。与 Flexbox(一维)不同,Grid 允许我们在两个维度上对齐项目,是专门为解决复杂的网页布局问题而设计的。

a.a. Grid 核心组件

Grid 由以下组件组成:

  • Grid 容器 (Grid Container):应用了 display: grid; 的父元素。
  • Grid 项目 (Grid Item):Grid 容器的直接子元素。
  • 网格线 (Grid Line):构成网格结构的水平和垂直分界线。
  • 网格单元 (Grid Cell):由四条网格线包围的最小单位空间。
  • 网格区域 (Grid Area):由任意四条网格线包围的矩形区域,可以包含一个或多个网格单元。
alt text

b.b. 启用 Grid 布局

要将一个元素变为 Grid 容器,只需设置其 display 属性:

.container {
  display: grid;
}

2. 网格结构

定义网格的结构是使用 Grid 布局的第一步。

a.a. grid-template-columnsgrid-template-rows

这两个属性用于定义网格的列和行的大小(即“轨道”)。

.container {
  display: grid;
  /* 创建三列,宽度分别为 200px, 100px, 200px */
  grid-template-columns: 200px 100px 200px;
  /* 创建两行,高度都为 150px */
  grid-template-rows: 150px 150px;
}

b.b. fr 单位

fr (fractional unit) 单位是 Grid 布局的特色,代表网格容器中可用空间的一份。它允许我们创建灵活的、按比例分配的网格轨道。

.container {
  display: grid;
  /* 第一列固定 100px,剩余空间按 1:2 的比例分配给第二和第三列 */
  grid-template-columns: 100px 1fr 2fr;
}

c.c. repeat() 函数

当需要创建多个相同尺寸的轨道时,repeat() 函数可以极大地简化代码。

.container {
  display: grid;
  /* 等同于 1fr 1fr 1fr 1fr */
  grid-template-columns: repeat(4, 1fr);
  /* 创建 12 列,每列最小 20px,最大 1fr */
  grid-template-columns: repeat(12, minmax(20px, 1fr));
}

d.d. minmax() 函数

minmax() 函数用于为网格轨道定义一个最小和最大尺寸,这对于创建响应式布局非常有用。

.container {
  display: grid;
  /* 创建一个列,最小宽度为 200px,但可以放大以填充更多空间 */
  grid-template-columns: minmax(200px, 1fr);
}

e.e. gap 属性

gap 属性用于定义网格线之间的距离(即项目之间的“沟槽”)。

.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  /* 在所有行和列之间创建 20px 的间距 */
  gap: 20px;
  
  /* 也可以分别设置 */
  /* row-gap: 30px; */
  /* column-gap: 10px; */
}

3. 放置项目

Grid 提供了多种方式来将项目放置在网格中的指定位置。

a.a. 基于网格线放置

我们可以通过指定项目的起始和结束网格线来放置它。

  • grid-column-start / grid-column-end
  • grid-row-start / grid-row-end

通常使用它们的简写形式 grid-columngrid-row

.item-1 {
  /* 从第 1 条列网格线开始,到第 3 条列网格线结束 */
  grid-column: 1 / 3;
  /* 从第 1 条行网格线开始,到第 2 条行网格线结束 */
  grid-row: 1 / 2;
}

.item-2 {
  /* 使用 span 关键字,表示从第 3 条列网格线开始,跨越 1 个单元格 */
  grid-column: 3 / span 1;
}

b.b. grid-template-areas

这是 Grid 最直观的布局方式。我们可以在容器上“画出”布局,然后将项目分配到命名区域中:

  1. 在容器上定义区域
.container {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header header header header"
    "main   main   .      sidebar"
    "footer footer footer footer";
}

. 表示一个空的网格单元。

  1. 将项目分配到区域
.page-header { grid-area: header; }
.main-content { grid-area: main; }
.sidebar { grid-area: sidebar; }
.page-footer { grid-area: footer; }
alt text

4. 对齐

Grid 的对齐属性与 Flexbox 非常相似,但分为两个维度:块级轴(Block Axis,通常是列)内联轴(Inline Axis,通常是行)

a.a. 对齐整个网格:

当网格的总尺寸小于其容器时,我们使用 justify-contentalign-content 这两个属性来对齐整个网格

  • justify-content: 在内联轴(行方向)上对齐网格。
  • align-content: 在块级轴(列方向)上对齐网格。

它们的值包括:

  • start: 网格向容器的起始位置对齐。
  • end: 网格向容器的结束位置对齐。
  • center: 网格在容器中居中。
  • space-between: 网格轨道之间均匀分布空间,首尾轨道紧贴容器边缘。
  • space-around: 每个网格轨道两侧的间距相等,因此轨道之间的间距是轨道与容器边缘间距的两倍。
  • space-evenly: 所有网格轨道之间以及轨道与容器边缘之间的间距都完全相等。

b.b. 对齐网格内的项目

justify-itemsalign-items 这两个属性在容器上设置,用于定义所有项目在其分配的网格单元内的默认对齐方式。

  • justify-items: 在内联轴(行方向)上对齐项目。
  • align-items: 在块级轴(列方向)上对齐项目。

它们的值包括:

  • start: 项目向其单元格的起始边缘对齐。
  • end: 项目向其单元格的结束边缘对齐。
  • center: 项目在其单元格内居中。
  • stretch (默认值): 项目拉伸以填满其单元格的整个空间。

c.c. 对齐单个项目

justify-selfalign-self 这两个属性在单个项目上设置,用于覆盖容器的 justify-itemsalign-items 设置,其值与 justify-items / align-items 相同。

.container {
  display: grid;
  justify-items: start; /* 默认所有项目都靠左对齐 */
  align-items: stretch; /* 默认所有项目都垂直拉伸 */
}

.special-item {
  /* 覆盖容器的设置 */
  justify-self: center; /* 这个特殊项目将在其单元格内水平居中 */
  align-self: end;      /* 这个特殊项目将在其单元格内垂直靠下对齐 */
}

5. Grid 和 Flexbox 的区别

a.a. 核心区别

这两种容器的核性区别在于它们所表示的维度

  • Flexbox 是一维布局。它一次只能处理一个维度——要么是行,要么是列。它非常适合沿着单条轴线对齐元素。
  • Grid 是二维布局。它可以同时处理行和列,允许我们创建复杂的、对齐的网格结构。

b.b. 布局思路

在考虑使用哪种容器来布局时,我们可以依据内容优先 vs. 布局优先的判别标准:

  • Flexbox内容优先 (Content-first)。项目的尺寸和它们在容器中的流动方式对布局有很大影响。项目会“伸缩”以适应空间。
  • Grid布局优先 (Layout-first)。我们首先定义一个严格的网格结构,然后将项目放入这个结构的单元格中。布局的控制权在容器而非项目。

总体而言,两者的区别如下

特性FlexboxGrid
维度一维 (1D)二维 (2D)
最佳用途组件内部的对齐、简单的线性布局整个页面的宏观布局、复杂的二维结构
项目关系项目之间相互关联项目与网格线对齐,相对独立
换行简单的换行,但对齐控制有限强大的二维控制,没有“换行”概念

c.c. 使用策略

这两个容器不是竞争关系,而是合作关系。现代 CSS 布局通常会同时使用两者。

使用 Flexbox 的场景如下:当我们需要沿着一条线对齐一组元素时,Flexbox 是最佳选择。它非常适合组件级别的布局,如:

  • 导航栏菜单
  • 一组按钮的排列
  • 表单元素的对齐
  • 卡片组件中图片和文本的布局

使用 Grid 的场景如下:当我们需要创建一个整体页面结构或任何需要同时考虑行和列的复杂布局时,Grid 是很好的选择,如:

  • 经典页面布局(页眉、页脚、侧边栏、主内容)
  • 仪表盘 (Dashboard) 界面
  • 图片库或棋盘式布局
  • 需要严格对齐的表单

最强大的方法是将两者结合起来:**使用 Grid 进行宏观布局,使用 Flexbox 进行微观对齐。**例如,我们可以用 Grid 搭建页面的主要区域(如 header, main, sidebar),然后在这个 sidebar 区域内部,使用 Flexbox 来对齐里面的导航链接列表。

/* 宏观布局 */
.page-container {
  display: grid;
  grid-template-areas: "header" "main" "sidebar";
}

/* 微观对齐 */
.sidebar {
  grid-area: sidebar;
  display: flex; /* 在 sidebar 内部使用 Flexbox */
  flex-direction: column;
  justify-content: center; /* 垂直居中导航链接 */
}