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擅长:

  • 二维布局(行和列)
  • 页面级布局
  • 复杂的网格系统
  • 响应式布局

掌握这两个工具,并根据具体需求选择合适的方案,才能构建出灵活、高效的现代网页布局。


相关工具推荐: