Frontend · #css#grid#flexbox#layout

现代CSS布局:Grid与Flexbox高级技巧

2025.07.16 6 min 2.4k
// 目录 · contents

引言

CSS 布局从 float 到 Flexbox 到 Grid,经历了巨大的变革。如今,Flexbox 和 Grid 不再是”新特性”,而是日常布局的基础工具。本文将深入介绍 Flexbox 的高级模式、Grid 的模板区域与 subgrid、container queries 等现代特性,并提供一系列实用的布局方案(recipes)。

Flexbox 高级模式

核心轴线模型

graph LR
    subgraph "flex-direction: row"
        A["Main Axis →"]
        B["Cross Axis ↓"]
    end

    subgraph "flex-direction: column"
        C["Main Axis ↓"]
        D["Cross Axis →"]
    end

flex 简写属性详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* flex: <flex-grow> <flex-shrink> <flex-basis> */

.item-auto {
flex: 1 1 auto;
/* grow: 占据可用空间 */
/* shrink: 允许缩小 */
/* basis: 基于内容大小 */
}

.item-none {
flex: 0 0 auto;
/* 不增长也不缩小,保持固定大小 */
}

.item-fill {
flex: 1 0 0%;
/* 等分可用空间,忽略内容大小 */
}

/* Common shorthand equivalents */
.flex-initial { flex: 0 1 auto; } /* Default */
.flex-auto { flex: 1 1 auto; }
.flex-none { flex: 0 0 auto; }
.flex-1 { flex: 1 1 0%; }

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
57
58
59
60
61
62
63
/* 1. Holy Grail Layout */
.holy-grail {
display: flex;
flex-direction: column;
min-height: 100vh;
}

.holy-grail header,
.holy-grail footer {
flex: none; /* Fixed height */
}

.holy-grail main {
flex: 1; /* Takes remaining space */
display: flex;
}

.holy-grail .sidebar { flex: 0 0 250px; }
.holy-grail .content { flex: 1; }

/* 2. Sticky Footer */
.page {
display: flex;
flex-direction: column;
min-height: 100vh;
}

.page-content {
flex: 1;
}

.page-footer {
flex-shrink: 0;
}

/* 3. Centered content with max-width */
.center-content {
display: flex;
justify-content: center;
padding-inline: 1rem;
}

.center-content > * {
flex: 1;
max-width: 1200px;
}

/* 4. Equal height cards */
.card-grid {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}

.card {
flex: 1 1 300px; /* Grow/shrink, minimum 300px */
display: flex;
flex-direction: column;
}

.card-body {
flex: 1; /* Pushes footer to bottom */
}

gap 属性

1
2
3
4
5
6
7
/* gap works in both Flexbox and Grid */
.flex-container {
display: flex;
flex-wrap: wrap;
gap: 1rem; /* row-gap and column-gap */
gap: 1rem 2rem; /* row-gap column-gap */
}

CSS Grid 深入

Grid Template Areas — 可视化布局

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
.dashboard {
display: grid;
grid-template-areas:
"header header header"
"sidebar main aside"
"sidebar footer footer";
grid-template-columns: 250px 1fr 200px;
grid-template-rows: 60px 1fr 40px;
min-height: 100vh;
gap: 0;
}

.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }

/* Responsive: stack on mobile */
@media (max-width: 768px) {
.dashboard {
grid-template-areas:
"header"
"main"
"aside"
"sidebar"
"footer";
grid-template-columns: 1fr;
grid-template-rows: auto;
}
}
graph TB
    subgraph "Desktop Layout"
        A[header header header]
        B[sidebar]
        C[main]
        D[aside]
        E[sidebar continued]
        F[footer footer]
    end

    subgraph "Mobile Layout"
        G[header]
        H[main]
        I[aside]
        J[sidebar]
        K[footer]
    end

    style A fill:#3498db,color:#fff
    style C fill:#2ecc71,color:#fff
    style G fill:#3498db,color:#fff
    style H fill:#2ecc71,color:#fff

auto-fill vs auto-fit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* auto-fill: creates as many tracks as possible, even empty ones */
.grid-fill {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 1rem;
}

/* auto-fit: collapses empty tracks, allowing items to stretch */
.grid-fit {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}

/* Key difference:
- auto-fill: 3 items in 1200px container = 3 items + 3 empty columns
- auto-fit: 3 items in 1200px container = 3 items stretched to fill
*/

Grid 隐式轨道与自动放置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.masonry-like {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: minmax(100px, auto); /* Auto-size row height */
gap: 1rem;
}

/* Span multiple rows/columns */
.featured-item {
grid-column: span 2;
grid-row: span 2;
}

/* Dense packing — fills gaps */
.dense-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
grid-auto-flow: dense;
gap: 0.5rem;
}

Subgrid — 子网格对齐

Subgrid 允许子元素继承父 Grid 的轨道定义,实现跨组件的对齐:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* Parent grid */
.card-list {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
}

/* Card uses parent's column tracks for its rows */
.card {
display: grid;
grid-row: span 3; /* Card spans 3 rows */
grid-template-rows: subgrid; /* Inherit parent's row tracks */
gap: 0;
}

/* Result: all card titles, bodies, and footers align across cards */
.card-title { /* row 1 */ }
.card-body { /* row 2 */ }
.card-footer { /* row 3 */ }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* Before subgrid: titles and footers don't align */
/* After subgrid: perfect alignment across cards */

/* Real-world example: form layout */
.form {
display: grid;
grid-template-columns: auto 1fr;
gap: 1rem;
}

.form-group {
display: grid;
grid-column: 1 / -1;
grid-template-columns: subgrid;
align-items: center;
}

/* Labels and inputs perfectly aligned */
.form-group label { grid-column: 1; }
.form-group input { grid-column: 2; }

Container Queries

Container Queries 基于父容器尺寸而非视口尺寸响应布局变化:

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
/* Define a containment context */
.card-wrapper {
container-type: inline-size;
container-name: card;
}

/* Shorthand */
.card-wrapper {
container: card / inline-size;
}

/* Query the container's size */
.card {
display: flex;
flex-direction: column;
padding: 1rem;
}

@container card (min-width: 400px) {
.card {
flex-direction: row;
gap: 1.5rem;
}

.card-image {
flex: 0 0 200px;
}
}

@container card (min-width: 700px) {
.card {
padding: 2rem;
}

.card-title {
font-size: 1.5rem;
}
}
graph TD
    A[Container Queries vs Media Queries] --> B[Media Queries]
    A --> C[Container Queries]

    B --> B1[基于视口宽度]
    B --> B2[全局响应式]
    B --> B3[组件在不同位置<br/>表现不一致]

    C --> C1[基于容器宽度]
    C --> C2[组件级响应式]
    C --> C3[组件在任何位置<br/>都自适应]

    style B fill:#e74c3c,color:#fff
    style C fill:#2ecc71,color:#fff

Container Query Units

1
2
3
4
5
6
7
8
9
10
/* Container query length units */
.card-title {
/* cqw: 1% of container width */
/* cqh: 1% of container height */
/* cqi: 1% of container inline size */
/* cqb: 1% of container block size */

font-size: clamp(1rem, 3cqi, 2rem);
padding: 2cqi;
}

响应式布局模式

RAM 模式 (Repeat, Auto, Minmax)

1
2
3
4
5
6
7
8
9
10
11
12
/* The most versatile responsive grid pattern */
.responsive-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
gap: 1.5rem;
}

/* Works perfectly at any viewport width:
- Very narrow: 1 column (items can't be < 100%)
- Medium: 2-3 columns (each >= 300px)
- Wide: 4+ columns
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* Sidebar that collapses on narrow screens — no media query needed */
.with-sidebar {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}

.sidebar {
flex: 1 1 300px; /* Minimum 300px, grows */
}

.main-content {
flex: 999 1 0%; /* Takes most space */
min-width: 50%; /* Forces wrap when too narrow */
}

Pancake Stack

1
2
3
4
5
6
7
8
9
10
/* Header, hero, main content, footer — common page layout */
.pancake-stack {
display: grid;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}

/* Header sticks to top */
/* Main content fills remaining space */
/* Footer sticks to bottom */

CSS 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
/* Animate grid-template-columns */
.expandable-grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 1rem;
transition: grid-template-columns 0.3s ease;
}

.expandable-grid:has(.item:hover) {
grid-template-columns: 0.5fr 2fr 0.5fr;
}

.expandable-grid .item:hover {
/* The hovered item's column expands */
}

/* Animate with named grid areas */
.accordion-grid {
display: grid;
grid-template-rows: auto 0fr auto 0fr;
transition: grid-template-rows 0.3s ease;
}

.accordion-grid.open {
grid-template-rows: auto 1fr auto 0fr;
}

.accordion-content {
overflow: hidden;
}

实用布局方案集

瀑布流(CSS Only — 实验性)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* CSS Masonry (Chrome 128+ with flag) */
.masonry {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
grid-template-rows: masonry;
gap: 1rem;
}

/* Fallback: columns-based masonry */
.masonry-fallback {
columns: 3 250px;
column-gap: 1rem;
}

.masonry-fallback .item {
break-inside: avoid;
margin-bottom: 1rem;
}

居中术大全

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
/* 1. Grid place-items (simplest) */
.center-grid {
display: grid;
place-items: center;
min-height: 100vh;
}

/* 2. Flexbox */
.center-flex {
display: flex;
justify-content: center;
align-items: center;
}

/* 3. Margin auto in flex/grid */
.center-auto {
display: grid; /* or flex */
}
.center-auto > .child {
margin: auto;
}

/* 4. Position + translate (legacy but useful) */
.center-absolute {
position: absolute;
top: 50%;
left: 50%;
translate: -50% -50%;
}

/* 5. Modern: align-content on block elements (Chrome 123+) */
.center-block {
align-content: center;
min-height: 100vh;
}

响应式导航栏

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
.nav {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 1rem;
padding: 1rem;
}

.nav-logo {
flex: 0 0 auto;
margin-right: auto; /* Push other items to the right */
}

.nav-links {
display: flex;
gap: 1rem;
flex-wrap: wrap;
}

/* Container query version for component-level responsiveness */
.nav-wrapper {
container: nav / inline-size;
}

@container nav (max-width: 600px) {
.nav {
flex-direction: column;
align-items: stretch;
}

.nav-logo {
margin-right: 0;
text-align: center;
}

.nav-links {
flex-direction: column;
}
}

现代 CSS 布局特性速查

特性 适用场景 浏览器支持
Flexbox 一维布局(行或列) 全面支持
Grid 二维布局(行和列) 全面支持
Subgrid 子元素对齐到父 Grid Chrome 117+
Container Queries 组件级响应式 Chrome 105+
:has() 选择器 父选择器 Chrome 105+
CSS Nesting 嵌套样式规则 Chrome 120+
View Transitions 页面过渡动画 Chrome 111+
Masonry 瀑布流布局 实验性

总结

现代 CSS 布局能力已经极为强大。Flexbox 擅长一维排列(导航栏、卡片行),Grid 擅长二维布局(整页布局、复杂网格),两者应结合使用而非对立。Container Queries 的到来真正解决了组件级响应式的需求,是继 Media Queries 后最重要的 CSS 特性。建议在新项目中积极采用 subgrid 和 container queries,并使用 @supports 提供渐进增强的回退方案。

作者 · authorzt
发布 · date2025-07-16
篇幅 · length2.4k 字 · 6 min
许可 · licenseCC BY-SA 4.0
$ echo "comments" · 评论