0%

HTML 与 CSS 基础(7):Flex 布局与 Grid 布局

这篇文章将学习 CSS 的 Flex 布局和 Grid 布局。

Flex 布局

Flex(Flexible Box)布局,也称为 弹性盒子布局,是 CSS3 中常用的现代布局模型之一。采用 Flex 布局的元素,称为 Flex 容器,它的所有直系子元素自动成为容器成员,称为 Flex 项目(flex item)。Flex 布局 是轴线布局,只能指定 项目 针对轴线的位置,它特别适用于一维布局(行或列)。

轴线

Flexbox 的强大之处在于它不依赖于传统的 width 和 height 属性,而是依赖于主轴和交叉轴的动态概念。在 Flex 容器中,默认存在两条相互垂直的轴:

  • 主轴(Main Axis):Flex 项目主要沿着这个轴线排列
  • 交叉轴(Cross Axis):与主轴垂直的轴线

Flex 布局最重要的一点:主轴和交叉轴是相对的,会随着 flex-direction 的变化而互换:

flex-direction 主轴方向 交叉轴方向
row(默认)/row-reverse 水平方向 垂直方向
column/column-reverse 垂直方向 水平方向
  • row(默认值):主轴为水平方向,从左到右
  • row-reverse:主轴为水平方向,从右到左
  • column:主轴为垂直方向,从上到下
  • column-reverse:主轴为垂直方向,从下到上

由于主轴和交叉轴的方向是动态的,因此又有了如下概念,这些概念始终是相对于 Flex 容器的,而不是固定的屏幕方向(如上、下、左、右):

  • Main Start:主轴的开始位置(与边框的交叉点)
  • Main End:主轴的结束位置
  • Cross Start:交叉轴的开始位置
  • Cross End:交叉轴的结束位置

项目默认沿主轴排列。单个项目占据的主轴空间叫做 main size,占据的交叉轴空间叫做 cross size。例如在 display: flex 的布局下,默认的主轴方向是水平方向(flex-direction: row),也就是说,子元素会沿着水平排列:

  • 如果有 3 个元素,宽度分别为 100px、200px 和 150px,高度分别为 50px、70px 和 60px
  • 那么它们沿着主轴的空间分别是 100px、200px 和 150px
  • 那么它们的交叉轴空间分别是 50px、70px 和 60px

下图展示默认使用 flex-direction: row 时这些概念的示意图:

对齐属性

justify-content 是 Flex 布局中一个极其重要的属性,它定义了 Flex 项目在主轴 (Main Axis) 上的对齐方式和空间分布

  • flex-start(默认):靠主轴起点对齐 (Main Start),项目都集中在主轴的起始端
1
|██ ██ ██        |
  • flex-end:靠主轴终点对齐 (Main End),项目都集中在主轴的末端
1
|        ██ ██ ██|
  • center:居中对齐,项目集中在主轴的中央
1
|    ██ ██ ██   |
  • space-between:两端对齐,项目之间间距相等
1
|██    ██    ██|
  • space-around:每个项目两侧都有空间,中间间距是边缘的 2 倍
1
|  ██    ██    ██  |
  • space-evenly:所有间距完全相等,包括边缘和中间
1
|  ██   ██   ██  |

align-items 则控制项目在 交叉轴 (Cross Axis) 上的对齐,align-items 属性设置在 Flex 容器 上,并且它对单行 Flex 项目的对齐方式起作用。

  • stretch (默认):拉伸,如果项目未设置高度,或高度设为 auto,项目将拉伸至占满容器的整个交叉轴高度(长度)
  • flex-start:靠交叉轴起点(Cross Start)对齐
  • flex-end:靠交叉轴终点(Cross End)对齐
  • center:在交叉轴方向居中对齐
  • baseline:基线对齐,项目以它们的内容基线对齐

下面的示例,展示了 justify-contentalign-items 属性不同组合下的布局效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Flex 布局效果展示</title>
<style>
/* 容器样式 */
.flex-container {
display: flex;
/* 默认 flex-direction: row; (主轴水平) */
height: 150px; /* 容器高度固定,以便观察 align-items 效果 */
border: 2px solid #333;
margin-bottom: 20px;
background-color: #f0f0f0;
font-family: Arial, sans-serif;
}

/* 项目样式 */
.flex-item {
width: 50px;
height: 50px; /* 项目高度固定,以便观察对齐效果,而非拉伸效果 */
background-color: #007bff;
color: white;
display: flex; /* 内部也使用 flex 来居中内容 */
justify-content: center;
align-items: center;
font-size: 14px;
margin: 5px; /* 添加外边距方便观察间距 */
}

/* 特殊居中样式 */
.center-center {
justify-content: center;
align-items: center;
}

/* 空间分配样式 */
.space-between-center {
justify-content: space-between;
align-items: center;
}

/* 两端对齐样式 */
.start-end {
justify-content: flex-start; /* 水平靠左 */
align-items: flex-end; /* 垂直靠下 */
}

/* 拉伸样式 (align-items: stretch 的项目需要 height: auto) */
.stretch-example .flex-item {
height: auto; /* 允许项目高度被拉伸 */
}
.stretch-example {
align-items: stretch; /* 垂直拉伸 */
justify-content: flex-start;
}

</style>
</head>
<body>

<h1>Flex 布局效果展示 (默认: row)</h1>

<h2>1. 完美居中 (Center-Center)</h2>
<p><code>justify-content: center;</code> & <code>align-items: center;</code></p>
<div class="flex-container center-center">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
</div>

<h2>2. 两端对齐 + 垂直居中</h2>
<p><code>justify-content: space-between;</code> & <code>align-items: center;</code></p>
<div class="flex-container space-between-center">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
</div>

<h2>3. 靠左 (Main Start) + 靠下 (Cross End)</h2>
<p><code>justify-content: flex-start;</code> & <code>align-items: flex-end;</code></p>
<div class="flex-container start-end">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
</div>

<h2>4. 垂直拉伸 (Stretch)</h2>
<p><code>align-items: stretch;</code> (项目需设置 <code>height: auto;</code>)</p>
<div class="flex-container stretch-example">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
</div>

</body>
</html>

align-content 属性则专门用于处理 多行 (Multi-line) Flex 布局,用于控制多根轴线在交叉轴方向上整体的对齐和空间分布。例如当 flex-direction: row(主轴水平)时,align-content 控制的是多行项目在垂直方向上的分布:

  • stretch (默认):拉伸,轴线占满整个交叉轴
  • flex-start:靠交叉轴起点对齐
  • flex-end:靠交叉轴终点对齐
  • center:在交叉轴方向居中对齐
  • space-between:与交叉轴两端对齐,轴线之间的间隔平均分布
  • space-around:轴线间隔轴线与边框的间隔 大一倍
  • space-evenly:所有间距完全相等

flex 项目属性

以上讨论的都是 Flex 容器的属性,接下来列举和总结设置在 Flex 项目 上的六个主要属性。这些属性控制单个项目在容器中的行为、大小和顺序。

属性 作用 默认值 详细解释
order 排列顺序 0 定义项目的排列顺序。数值越小,项目越靠前,可以是负数。
flex-grow 放大比例 0 定义当容器有剩余空间时,项目将占据的放大比例。0 表示不放大。
flex-shrink 缩小比例 1 定义当容器空间不足时,项目将收缩的比例。0 表示不缩小。
flex-basis 主轴基准值 auto 定义项目在分配剩余空间之前,在主轴上占据的初始尺寸。
flex 简写属性 0 1 auto 是 flex-grow、flex-shrink 和 flex-basis 的简写。
align-self 单项对齐 auto 允许单个项目有不同于容器 align-items 的对齐方式,覆盖容器的设置。

Grid 布局

Grid 布局(网格布局)是 CSS 中最强大的二维布局系统。它允许您同时在行 (Rows) 和 列 (Columns) 两个维度上控制元素的排列和定位,非常适合创建复杂的网页结构和响应式设计。与 Flexbox(一维布局,只能沿着主轴或交叉轴排列)相比,Grid 布局更擅长将整个页面划分成主要区域。

网格布局中,存在如下基本概念:

  • 网格容器(Grid Container):指设置了 display: griddisplay: inline-grid 的元素。它是整个网格系统的父元素
  • 网格项目(Grid Item)则是网格容器的直接子元素,它们将在网格中进行定位和布局,
  • 网格线(Grid Line):划分网格的水平和垂直分界线。它们从 1 开始编号
  • 网格轨道(Grid Track):两条相邻网格线之间的空间,即网格的行或列
  • 网格单元(Grid Cell:由两条行网格线和两条列网格线围成的最小区域(类似表格的单元格)
  • 网格区域(Grid Area):由任意数量的网格单元组成的矩形区域,可用于放置一个网格项目

容器属性

首先介绍网格容器的相关属性。display: grid 将元素设置为网格容器:

1
.container { display: grid; }

容器指定了网格布局以后,接着就要划分行和列。grid-template-rows:定义行的数量和每行的高度,对于如下配置

1
grid-template-rows: 100px auto 1fr;
  • 第一行高 100px,第二行高度自适应内容,第三行占据剩余空间
  • fr 单位: 代表 分数 (Fraction)。它用于按比例分配网格容器中的可用空间,例如,1fr 2fr 代表后者是前者的 2 倍

grid-template-columns 定义列的数量和每列的宽度:

1
grid-template-columns: repeat(3, 1fr);
  • 创建 3 列,每列平均分配剩余空间

grid-template-areas 通过名称来定义网格区域,简化布局:

1
grid-template-areas: "header header header" "sidebar main main";
  • 将容器划分成三个列,两行,并命名了区域

需要注意,区域的命名会影响到网格线:

  • 每个区域的起始网格线,会自动命名为 区域名-start,终止网格线自动命名为 区域名-end

grid-row-gapgrid-column-gap 设置网格单元之间的行间距和列间距。grid-gap 属性是 grid-column-gapgrid-row-gap 的合并简写形式。

划分网格以后,容器的子元素会按照顺序,自动放置在每一个网格。grid-auto-flow 属性决定了它们是按行填充还是按列填充,以及是否允许项目跨越多个单元格。

  • row (默认值):按行填充,项目从网格的第一行开始,依次填充可用的列。当一行被填满后,布局会移动到下一行
  • column:按列填充,项目从网格的第一列开始,依次填充可用的行。当一列被填满后,布局会移动到下一列
  • dense:密集填充,网格算法会尝试回填前面留下的任何小空隙。它会向前查找,找到一个适合当前项目尺寸的空位,即使这个空位在顺序上比当前项目靠前。rowcolumn 都可以与 dense 关键字结合使用,以优化空间利用

justify-items 属性设置单元格内容的水平位置(左中右),align-items 属性设置单元格内容的垂直位置(上中下),他们的取值可以是。

  • start:对齐单元格的起始边缘
  • end:对齐单元格的结束边缘
  • center:单元格内部居中
  • stretch:拉伸,占满单元格的整个宽度(默认值)

place-items 属性是 align-items 属性和 justify-items 属性的合并简写形式。

justify-content 属性是整个内容区域在容器里面的水平位置(左中右),align-content 属性是整个内容区域的垂直位置(上中下)。

项目属性

接下来介绍 Grid 布局中应用于网格项目 (Grid Item) 的主要属性,这些属性控制着单个项目在网格容器内的具体位置、大小和对齐方式。

  • grid-column-start:定义项目在垂直网格线上开始的位置(左边界)。
  • grid-column-end:定义项目在垂直网格线上结束的位置(右边界)
  • grid-row-start:定义项目在水平网格线上开始的位置(上边界)。
  • grid-row-end:定义项目在水平网格线上结束的位置(下边界)。
  • grid-column:grid-column-startgrid-column-end 的合并简写形式
  • grid-row:grid-row-startgrid-row-end 的合并简写形式
  • grid-area:指定项目放在哪一个区域
  • justify-self:属性设置单元格内容的水平位置(左中右),跟 justify-items 属性的用法完全一致,但只作用于单个项目
  • align-self:属性设置单元格内容的垂直位置(上中下),跟 align-items 属性的用法完全一致,也是只作用于单个项目
  • z-index:控制网格项目的堆叠顺序。当项目发生重叠时,z-index 值更高的项目会显示在更前面

简单示例

如下是 Grid 布局的一个简单示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS Grid 布局 - 单文件示例</title>

<style>
/* --- 容器基础样式 --- */
.grid-container {
display: grid; /* 激活 Grid 布局 */

/* 定义 3 列:150px, 占据剩余空间 (1fr), 100px */
grid-template-columns: 150px 1fr 100px;

/* 定义 4 行:50px, 150px, 150px, 50px */
grid-template-rows: 50px 150px 150px 50px;

/* 网格间距 */
gap: 10px;

/* 容器居中和边界 */
width: 80%;
max-width: 900px;
margin: 20px auto;
border: 2px solid #333;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

/* --- 子元素基础样式 --- */
.grid-item {
background-color: lightblue;
color: #333;
padding: 10px;
border: 1px solid #007bff;
display: flex; /* 使用 flex 让内容居中 */
justify-content: center;
align-items: center;
text-align: center;
font-weight: bold;
font-size: 1.1em;
}

/* --- 放置和跨越子元素 --- */

/* item-1 (Header) 位于第 1 行,跨越所有 3 列 */
.item-1 {
grid-column: 1 / span 3;
grid-row: 1;
background-color: #007bff;
color: white;
}

/* item-2 (Sidebar) 位于第 2 行、第 1 列 */
.item-2 {
grid-row: 2;
grid-column: 1;
background-color: #6c757d;
color: white;
}

/* item-3 (Main Content) 位于第 2 列,跨越第 2 和第 3 行 */
.item-3 {
grid-row: 2 / span 2; /* 从第 2 条线开始,跨越 2 行 */
grid-column: 2;
background-color: #28a745;
color: white;
}

/* item-4 (Ad) 位于第 2 行、第 3 列 */
.item-4 {
grid-row: 2;
grid-column: 3;
background-color: #ffc107;
}

/* item-6 (Another Item) 位于第 3 行、第 1 列 */
.item-6 {
grid-row: 3;
grid-column: 1;
background-color: #adb5bd;
}

/* item-5 (Footer) 位于第 4 行,跨越所有 3 列 */
.item-5 {
grid-row: 4;
grid-column: 1 / -1; /* 从第 1 条线到最后一条线 (-1) */
background-color: #007bff;
color: white;
}
</style>
</head>
<body>

<h1>CSS Grid 简单布局演示</h1>

<div class="grid-container">
<div class="grid-item item-1">Header (1 / span 3)</div>

<div class="grid-item item-2">Sidebar (2 / 1)</div>
<div class="grid-item item-3">Main Content (2 / span 2)</div> <div class="grid-item item-4">Ad (2 / 3)</div>

<div class="grid-item item-6">Another Item (3 / 1)</div>
<div class="grid-item item-5">Footer (4 / span 3)</div>

</div>
</body>
</html>

Reference