CSS Grid和Flexbox是现代CSS布局的两大支柱。虽然两者都能实现复杂的布局效果,但各自有不同的特点和适用场景。本文将通过丰富的实例对比,帮助你掌握这两个强大的布局工具。
1. 理解Grid和Flexbox的本质区别#
一维 vs 二维布局#
1
2
3
4
5
6
7
8
9
10
11
| /* Flexbox - 一维布局 */
.flex-container {
display: flex;
/* 只能在一个方向上排列项目 */
}
/* Grid - 二维布局 */
.grid-container {
display: grid;
/* 可以同时在行和列上控制项目 */
}
|
核心区别:
- Flexbox:一维布局(行或列)
- Grid:二维布局(行和列)
内容驱动 vs 布局驱动#
1
2
3
4
5
6
7
8
9
10
11
| /* Flexbox - 内容驱动 */
/* 项目的大小和位置主要由内容决定 */
.flex-item {
flex: 1 1 200px; /* 基于内容的弹性伸缩 */
}
/* Grid - 布局驱动 */
/* 网格的尺寸和位置由容器定义 */
.grid-container {
grid-template-columns: 1fr 2fr 1fr; /* 明确的列定义 */
}
|
2. Flexbox实战技巧#
弹性导航栏#
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
| .navbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 2rem;
height: 60px;
background: #2c3e50;
color: white;
}
.navbar-brand {
flex: 0 0 auto;
font-size: 1.5rem;
font-weight: bold;
}
.navbar-menu {
display: flex;
gap: 2rem;
list-style: none;
margin: 0;
padding: 0;
}
.navbar-actions {
display: flex;
gap: 1rem;
align-items: center;
}
/* 响应式导航 */
@media (max-width: 768px) {
.navbar {
flex-wrap: wrap;
height: auto;
padding: 1rem;
}
.navbar-menu {
flex: 0 0 100%;
order: 3;
flex-direction: column;
gap: 0;
margin-top: 1rem;
background: #34495e;
padding: 1rem;
border-radius: 0.5rem;
}
}
|
垂直居中解决方案#
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
| /* 方案1:Flexbox垂直居中 */
.center-container {
display: flex;
align-items: center; /* 垂直居中 */
justify-content: center; /* 水平居中 */
height: 100vh;
}
/* 方案2:Flexbox + margin:auto */
.center-container {
display: flex;
height: 100vh;
}
.center-item {
margin: auto;
}
/* 方案3:嵌套Flexbox */
.vertical-center {
display: flex;
align-items: center;
}
.horizontal-center {
display: flex;
justify-content: center;
width: 100%;
}
|
等高列布局#
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
| .card-container {
display: flex;
gap: 2rem;
margin: 2rem 0;
}
.card {
flex: 1;
display: flex;
flex-direction: column;
border: 1px solid #ddd;
border-radius: 0.5rem;
overflow: hidden;
}
.card-header {
padding: 1rem;
background: #f8f9fa;
border-bottom: 1px solid #ddd;
}
.card-content {
padding: 1rem;
flex: 1; /* 填充剩余空间 */
}
.card-footer {
padding: 1rem;
background: #f8f9fa;
border-top: 1px solid #ddd;
margin-top: auto; /* 推到底部 */
}
|
自适应表单布局#
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
| .form-group {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.form-row {
display: flex;
gap: 1rem;
flex-wrap: wrap;
}
.form-field {
flex: 1 1 250px; /* 基础宽度250px,可伸缩 */
min-width: 200px; /* 最小宽度 */
}
.form-label {
display: block;
font-weight: 500;
margin-bottom: 0.25rem;
color: #374151;
}
.form-input {
width: 100%;
padding: 0.5rem 0.75rem;
border: 1px solid #d1d5db;
border-radius: 0.375rem;
font-size: 1rem;
}
.form-actions {
display: flex;
gap: 1rem;
justify-content: flex-end;
margin-top: 2rem;
}
.btn {
padding: 0.5rem 1.5rem;
border: none;
border-radius: 0.375rem;
font-size: 1rem;
cursor: pointer;
transition: all 0.2s;
}
.btn-primary {
background: #3b82f6;
color: white;
}
.btn-secondary {
background: #6b7280;
color: white;
}
|
3. Grid实战技巧#
经典的12列网格系统#
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
| .grid-container {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 1rem;
max-width: 1200px;
margin: 0 auto;
padding: 0 1rem;
}
/* 列跨度工具类 */
.col-1 { grid-column: span 1; }
.col-2 { grid-column: span 2; }
.col-3 { grid-column: span 3; }
.col-4 { grid-column: span 4; }
.col-6 { grid-column: span 6; }
.col-8 { grid-column: span 8; }
.col-12 { grid-column: span 12; }
/* 行跨度工具类 */
.row-1 { grid-row: span 1; }
.row-2 { grid-row: span 2; }
/* 响应式列 */
@media (max-width: 768px) {
.col-sm-12 { grid-column: span 12; }
.col-sm-6 { grid-column: span 6; }
.col-sm-4 { grid-column: span 4; }
}
/* 使用示例 */
.layout-example {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 1rem;
}
.header {
grid-column: 1 / -1; /* 从第1列到最后一列 */
height: 80px;
}
.sidebar {
grid-column: span 3; /* 占3列 */
}
.main-content {
grid-column: span 9; /* 占9列 */
}
|
复杂的页面布局#
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
| .page-layout {
display: grid;
grid-template-areas:
"header header header"
"sidebar main aside"
"footer footer footer";
grid-template-columns: 250px 1fr 200px;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
gap: 1rem;
}
.header {
grid-area: header;
background: #1f2937;
color: white;
padding: 1rem 2rem;
}
.sidebar {
grid-area: sidebar;
background: #f3f4f6;
padding: 1.5rem;
}
.main-content {
grid-area: main;
padding: 1.5rem;
overflow-y: auto;
}
.aside {
grid-area: aside;
background: #f9fafb;
padding: 1.5rem;
}
.footer {
grid-area: footer;
background: #374151;
color: white;
padding: 1rem 2rem;
text-align: center;
}
/* 响应式布局调整 */
@media (max-width: 1024px) {
.page-layout {
grid-template-areas:
"header header"
"main main"
"sidebar sidebar"
"aside aside"
"footer footer";
grid-template-columns: 1fr;
grid-template-rows: auto 1fr auto auto auto;
}
}
|
卡片网格布局#
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
| .card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
padding: 2rem 0;
}
.product-card {
background: white;
border-radius: 0.5rem;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
overflow: hidden;
transition: transform 0.2s, box-shadow 0.2s;
}
.product-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.15);
}
.card-image {
width: 100%;
height: 200px;
object-fit: cover;
}
.card-body {
padding: 1.5rem;
}
.card-title {
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 0.5rem;
color: #1f2937;
}
.card-price {
font-size: 1.5rem;
font-weight: bold;
color: #059669;
margin: 1rem 0;
}
.card-actions {
display: flex;
gap: 0.5rem;
}
/* 自适应列数控制 */
.card-grid-2 {
grid-template-columns: repeat(2, 1fr);
}
.card-grid-3 {
grid-template-columns: repeat(3, 1fr);
}
.card-grid-4 {
grid-template-columns: repeat(4, 1fr);
}
|
图片画廊布局#
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
| .gallery {
display: grid;
grid-template-rows: auto 200px 150px;
grid-template-columns: repeat(4, 1fr);
gap: 0.5rem;
height: 500px;
}
.gallery-item {
overflow: hidden;
border-radius: 0.5rem;
}
.gallery-item img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s;
}
.gallery-item:hover img {
transform: scale(1.05);
}
/* 特色图片 */
.gallery-item:nth-child(1) {
grid-column: span 2;
grid-row: span 2;
}
.gallery-item:nth-child(2) {
grid-column: span 2;
grid-row: span 1;
}
/* 瀑布流布局 */
.masonry {
display: grid;
grid-template-rows: masonry;
gap: 1rem;
}
/* 使用CSS columns实现的瀑布流 */
.masonry-fallback {
column-count: 4;
column-gap: 1rem;
}
.masonry-item {
break-inside: avoid;
margin-bottom: 1rem;
}
|
4. 混合布局技巧#
Grid + Flexbox组合#
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
| /* 使用Grid定义整体布局,Flexbox处理内部对齐 */
.dashboard {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: 60px 1fr;
grid-template-areas:
"sidebar header"
"sidebar main";
height: 100vh;
}
.sidebar {
grid-area: sidebar;
background: #1f2937;
color: white;
}
.header {
grid-area: header;
background: white;
border-bottom: 1px solid #e5e7eb;
}
.main {
grid-area: main;
background: #f9fafb;
overflow-y: auto;
}
/* 在Grid内部使用Flexbox */
.widget {
background: white;
border-radius: 0.5rem;
padding: 1.5rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.widget-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid #e5e7eb;
}
.widget-title {
font-size: 1.125rem;
font-weight: 600;
color: #1f2937;
}
.widget-actions {
display: flex;
gap: 0.5rem;
}
|
响应式布局策略#
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
| /* 移动优先的响应式设计 */
.responsive-layout {
display: grid;
gap: 1rem;
/* 移动端默认单列 */
grid-template-columns: 1fr;
}
/* 平板设备 */
@media (min-width: 768px) {
.responsive-layout {
grid-template-columns: repeat(2, 1fr);
}
}
/* 桌面设备 */
@media (min-width: 1024px) {
.responsive-layout {
grid-template-columns: repeat(3, 1fr);
}
}
/* 大屏设备 */
@media (min-width: 1280px) {
.responsive-layout {
grid-template-columns: repeat(4, 1fr);
}
}
/* 使用CSS变量实现灵活布局 */
.dynamic-grid {
--columns: 1;
--gap: 1rem;
display: grid;
grid-template-columns: repeat(var(--columns), 1fr);
gap: var(--gap);
}
/* JavaScript控制变量 */
// document.documentElement.style.setProperty('--columns', '3');
|
5. 高级布局模式#
Holy Grail布局#
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
| .holy-grail {
display: grid;
grid-template-columns: auto 1fr auto;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
min-height: 100vh;
gap: 1rem;
}
.holy-grail > header {
grid-area: header;
background: #1f2937;
color: white;
padding: 1rem;
}
.holy-grail > nav {
grid-area: nav;
background: #f3f4f6;
padding: 1rem;
}
.holy-grail > main {
grid-area: main;
background: white;
padding: 1rem;
}
.holy-grail > aside {
grid-area: aside;
background: #f9fafb;
padding: 1rem;
}
.holy-grail > footer {
grid-area: footer;
background: #374151;
color: white;
padding: 1rem;
text-align: center;
}
|
圣杯布局的Flexbox实现#
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
| .holy-grail-flex {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.holy-grail-flex > header,
.holy-grail-flex > footer {
flex: 0 0 auto;
}
.holy-grail-flex > .content {
flex: 1 1 auto;
display: flex;
}
.holy-grail-flex > .content > nav {
flex: 0 0 200px;
order: -1;
}
.holy-grail-flex > .content > main {
flex: 1 1 auto;
}
.holy-grail-flex > .content > aside {
flex: 0 0 200px;
}
|
重叠布局效果#
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
| .stack-layout {
display: grid;
grid-template-areas: "stack";
place-items: center;
height: 400px;
}
.stack-item {
grid-area: stack;
}
/* 创建多层重叠效果 */
.stack-item:nth-child(1) {
z-index: 3;
transform: scale(0.9);
opacity: 0.9;
}
.stack-item:nth-child(2) {
z-index: 2;
transform: scale(0.95);
opacity: 0.95;
}
.stack-item:nth-child(3) {
z-index: 1;
transform: scale(1);
opacity: 1;
}
|
6. 性能优化技巧#
减少重排重绘#
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
| /* 使用transform代替left/top */
.animation-container {
position: relative;
width: 100px;
height: 100px;
}
.animated-element {
position: absolute;
left: 0;
/* 好的做法:使用transform */
transform: translateX(0);
transition: transform 0.3s ease;
}
.animated-element.active {
transform: translateX(100px);
/* 避免:修改left属性 */
/* left: 100px; */
}
/* 使用will-change提示浏览器 */
.optimize-performance {
will-change: transform, opacity;
}
/* 动画结束后移除will-change */
.animation-complete {
will-change: auto;
}
|
布局性能考虑#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| /* 避免复杂的Grid计算 */
.simple-grid {
/* 好的做法:明确尺寸 */
display: grid;
grid-template-columns: 200px 1fr 200px;
}
.complex-grid {
/* 避免:复杂的fr计算 */
display: grid;
grid-template-columns:
minmax(100px, max-content)
repeat(auto-fit, minmax(200px, 1fr))
minmax(100px, max-content);
}
/* 使用contain属性优化 */
.optimized-element {
contain: layout;
/* 告诉浏览器元素的子树不会影响页面其他部分 */
}
|
7. 调试和工具#
可视化调试#
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
| /* Grid调试样式 */
.grid-debug {
display: grid;
gap: 1rem;
}
.grid-debug::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image:
linear-gradient(rgba(255, 0, 0, 0.1) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 0, 0, 0.1) 1px, transparent 1px);
background-size: 50px 50px;
pointer-events: none;
z-index: 1000;
}
/* Flexbox调试 */
.flex-debug {
outline: 2px solid rgba(0, 255, 0, 0.5);
}
.flex-debug > * {
outline: 1px solid rgba(0, 0, 255, 0.3);
}
|
浏览器开发者工具#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| /* 在Chrome DevTools中测试 */
.test-layout {
display: grid;
/* 右键检查 -> Layout -> Grid */
grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto 1fr auto;
gap: 1rem;
}
/* Flexbox调试 */
.test-flex {
display: flex;
/* 在DevTools中可以查看Flexbox信息 */
justify-content: space-between;
align-items: center;
}
|
选择建议#
何时使用Flexbox#
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
| /* ✅ 推荐使用Flexbox的场景 */
/* 1. 导航栏布局 */
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
}
/* 2. 表单控件对齐 */
.form-group {
display: flex;
align-items: center;
gap: 0.5rem;
}
/* 3. 垂直居中 */
.center {
display: flex;
align-items: center;
justify-content: center;
}
/* 4. 等高列 */
.equal-height {
display: flex;
}
.equal-height > * {
flex: 1;
}
|
何时使用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
| /* ✅ 推荐使用Grid的场景 */
/* 1. 页面整体布局 */
.page-layout {
display: grid;
grid-template-areas:
"header header header"
"sidebar main aside"
"footer footer footer";
}
/* 2. 卡片网格 */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1rem;
}
/* 3. 复杂的二维布局 */
.dashboard {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: auto 1fr auto;
gap: 1rem;
}
/* 4. 图片画廊 */
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 0.5rem;
}
|
CSS Grid和Flexbox都是强大的布局工具,它们不是竞争关系,而是互补关系:
Flexbox擅长:
- 一维布局(行或列)
- 内容对齐和分布
- 组件级布局
- 垂直居中
Grid擅长:
- 二维布局(行和列)
- 页面级布局
- 复杂的网格系统
- 响应式布局
掌握这两个工具,并根据具体需求选择合适的方案,才能构建出灵活、高效的现代网页布局。
相关工具推荐: