两种布局的定位

  • Flexbox:一维布局(一个方向排布),适合”在一条线里怎么分配“。
  • Grid:二维布局(行和列同时控制),适合”整个页面/区块怎么切分“。

简单记:Flex 管”线”,Grid 管”面”。

一、Flexbox 核心

容器设 display: flex 后,子项沿主轴排列。两根轴:

1
2
主轴 main axis(默认水平)  ── justify-content 控制
交叉轴 cross axis(垂直) ── align-items 控制
1
2
3
4
5
6
7
8
9
10
11
.container {
display: flex;
justify-content: center; /* 主轴:start/center/space-between/space-around */
align-items: center; /* 交叉轴:start/center/stretch */
flex-wrap: wrap; /* 换行 */
gap: 12px; /* 子项间距(现代浏览器都支持) */
}

.item {
flex: 1; /* 简写:flex-grow flex-shrink flex-basis */
}

flex: 1 的含义:flex: 1 1 0%,允许伸缩、基准为 0,即”平分剩余空间”。这是自适应布局最常用的写法。

经典场景——两栏/三栏布局:

1
2
3
4
5
6
7
8
9
10
.layout {
display: flex;
}
.sidebar {
width: 240px;
flex-shrink: 0; /* 不收缩 */
}
.main {
flex: 1; /* 占满剩余 */
}

二、Grid 核心

Grid 用”线”划分网格,子项放进去:

1
2
3
4
5
6
7
8
9
10
11
.container {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 三等分 */
grid-template-rows: auto 1fr auto; /* 上中下 */
gap: 16px;
}

.item {
grid-column: 1 / 3; /* 占第 1 列到第 3 列(跨两列) */
grid-row: 1 / 2;
}

1fr 是 Grid 特有的弹性单位,代表”一份可用空间”,类似 Flex 的 flex: 1。

实战:经典页面骨架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.page {
display: grid;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
grid-template-columns: 240px 1fr;
grid-template-rows: 60px 1fr 40px;
min-height: 100vh;
}

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

grid-template-areas 用 ASCII 画布定义区域,可读性极高,适合页面级骨架。

响应式:auto-fit 与 minmax

1
2
3
4
5
.card-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 16px;
}

minmax(280px, 1fr) + auto-fill:卡片最少 280px,放不下就换行,自动填充。一行代码实现响应式卡片墙,这是 Grid 最爽的场景。

三、选型对比表

场景 推荐 原因
导航栏、按钮组、图标排列 Flexbox 一行内分配,语义简单
垂直水平居中 Flexbox justify-content + align-items 两行搞定
两栏/三栏侧边栏布局 Flexbox 或 Grid Flex 够用,Grid 更可控
整页骨架(头部/侧栏/主体/底部) Grid 二维区域划分是 Grid 主场
卡片网格、瀑布流 Grid repeat + minmax 天然响应式
单行内某个元素弹性伸缩 Flexbox flex: 1 最直观

经验法则:不确定时,先想”这是一维问题还是二维问题”。一维用 Flex,二维用 Grid;两者可以嵌套(Grid 单元格里再 Flex)。

四、从老布局迁移的实战

场景:图标 + 文字垂直居中(老写法是 float + line-height 黑魔法)

1
2
3
4
5
6
/* 现代写法 */
.nav-item {
display: inline-flex;
align-items: center;
gap: 6px;
}

场景:三等分按钮

1
2
3
4
5
6
7
8
/* 老写法:width: 33.33% + 处理边框 */
/* 现代写法 */
.btn-group {
display: flex;
}
.btn-group button {
flex: 1;
}

场景:底部固定页脚(sticky footer)

1
2
3
4
5
6
7
8
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
main {
flex: 1; /* 内容区撑开,页脚永远贴底 */
}

常见坑

  1. flex 子项被压缩:内容过长时子项被挤扁,加 min-width: 0 或 flex-shrink: 0;
  2. gap 兼容性:现代浏览器都支持了,但极老浏览器需要 margin 兜底;
  3. Grid 的 1fr 最小尺寸:内容溢出时 1fr 不收缩,配合 minmax(0, 1fr) 解决;
  4. Flex 垂直居中失效:检查父容器有没有 height,没有高度就没有”垂直”可言。

总结

Flexbox 和 Grid 不是竞争关系,是互补关系。掌握这两套布局后,传统 float 布局可以直接淘汰。建议从”Flex 处理组件内部、Grid 处理页面骨架”这个分工开始实践。