一篇讲透
display: flex与display: grid:从基本概念到每一个属性,全部附代码示例与效果说明,最后给出两者的对比与选型建议。
项目示例预览地址
一、Flex 弹性布局
1.1 基本概念
Flex 是"一维"布局,只处理一个方向(主轴)上的排列。
css
.container {
display: flex; /* 或 inline-flex */
}
关键概念:
- 主轴(main axis) :由
flex-direction决定,默认水平(row),项目沿主轴排列; - 交叉轴(cross axis):与主轴垂直的方向;
- 主起/主尾、交叉起/交叉尾:主轴和交叉轴的起点与终点;
- 容器(flex container) :设置
display: flex的元素; - 项目(flex item):容器的直接子元素。
ini
主轴方向(flex-direction: row)
┌──────────────────────────────────────┐
│ [item1] [item2] [item3] [item4] │ ← 项目沿主轴排列
│ │
│ │ ← 交叉轴方向(垂直)
└──────────────────────────────────────┘
示例:
html
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
css
.container {
display: flex;
background: #f0f4ff;
padding: 16px;
}
.item {
background: #409eff;
color: #fff;
width: 80px;
height: 80px;
margin: 8px;
display: flex;
justify-content: center;
align-items: center;
}
1.2 容器属性(写在父元素上)
① flex-direction ------ 主轴方向
| 取值 | 效果 |
|---|---|
row(默认) |
水平从左到右 |
row-reverse |
水平从右到左 |
column |
垂直从上到下 |
column-reverse |
垂直从下到上 |
css
.container { flex-direction: row; } /* 默认:→ → → */
.container { flex-direction: row-reverse; } /* ← ← ← */
.container { flex-direction: column; } /* 竖排:↓↓↓ */
.container { flex-direction: column-reverse; } /* ↑↑↑ */
注意:
row-reverse/column-reverse不只是换方向,主轴的起点终点也互换,justify-content的对齐起点会跟着变。
② flex-wrap ------ 是否换行
| 取值 | 效果 |
|---|---|
nowrap(默认) |
不换行,空间不足时项目被压缩 |
wrap |
换行,多行排列 |
wrap-reverse |
换行,且新行从交叉轴反向开始 |
css
.container { flex-wrap: wrap; } /* 放不下就换到下一行 */
.container { flex-wrap: nowrap; } /* 默认,强行塞一行 */
.container { flex-wrap: wrap-reverse; } /* 换行且反向 */
③ flex-flow ------ flex-direction + flex-wrap 简写
css
.container {
/* flex-direction: row; flex-wrap: wrap; */
flex-flow: row wrap;
}
④ justify-content ------ 主轴方向的对齐
| 取值 | 效果 |
|---|---|
flex-start(默认) |
靠主起点 |
flex-end |
靠主终点 |
center |
居中 |
space-between |
两端对齐,项目间间距相等 |
space-around |
每项两侧有相等的空间 |
space-evenly |
所有间隙完全相等 |
css
.container {
display: flex;
justify-content: space-between; /* 典型:导航栏左右分布 */
}
ini
justify-content: space-between
[item1] [item2] [item3]
justify-content: space-evenly
[item1] [item2] [item3]
⑤ align-items ------ 交叉轴方向的对齐(单行)
| 取值 | 效果 |
|---|---|
stretch(默认) |
拉伸填满交叉轴高度 |
flex-start |
靠交叉起点 |
flex-end |
靠交叉终点 |
center |
交叉轴居中 |
baseline |
按文字基线对齐 |
css
.container {
display: flex;
align-items: center; /* 最常用:垂直居中 */
}
经典实现水平垂直居中 :
justify-content: center; align-items: center;
⑥ align-content ------ 多行时交叉轴的对齐
当 flex-wrap: wrap 产生多行时才生效,取值同 justify-content(外加 stretch)。
css
.container {
display: flex;
flex-wrap: wrap;
align-content: space-between; /* 多行整体在交叉轴分布 */
height: 400px;
}
区别:
align-items控制"每一行内项目"的对齐;align-content控制"多行整体"的分布。单行时align-content无效。
⑦ gap ------ 项目间距
css
.container {
display: flex;
gap: 16px; /* 行、列间距都是 16px */
row-gap: 12px; /* 行间距 */
column-gap: 8px; /* 列间距 */
}
gap比margin更好用:不影响两端、不会把间距算进flex-basis。
1.3 项目属性(写在子元素上)
① order ------ 排列顺序
数值越小越靠前,默认 0,可为负数。
css
.item-1 { order: 3; }
.item-2 { order: 1; }
.item-3 { order: 2; }
/* 显示顺序:item-2 → item-3 → item-1 */
② flex-grow ------ 放大比例
默认 0(不放大)。当容器有剩余空间时,按比例分配。
css
.container { display: flex; width: 600px; }
.item { flex-grow: 1; } /* 平均分剩余空间 */
.item-big { flex-grow: 2; } /* 占比是别的项目的 2 倍 */
css
剩余空间 300px
[ A:flex-grow 1 ][ B:flex-grow 2 ] → A 分 100px,B 分 200px
③ flex-shrink ------ 缩小比例
默认 1(空间不足时允许缩小)。设为 0 则不缩小(保持原尺寸,可能溢出)。
css
.item { flex-shrink: 0; } /* 不缩小,宽度固定 */
.item { flex-shrink: 2; } /* 空间不足时缩小的程度更大 */
④ flex-basis ------ 初始主轴尺寸
项目在"放大/缩小之前"的基准尺寸,默认 auto(取自身 width/height)。
css
.item { flex-basis: 200px; } /* 先按 200px 算,再参与 grow/shrink */
.item { flex-basis: 50%; }
⑤ flex ------ flex-grow flex-shrink flex-basis 简写
| 写法 | 等价 | 含义 |
|---|---|---|
flex: 1 |
1 1 0% |
等分剩余空间(最常用) |
flex: auto |
1 1 auto |
按内容大小 + 参与伸缩 |
flex: none |
0 0 auto |
固定尺寸,不伸缩 |
flex: 0 1 auto |
默认 | 可缩小不可放大 |
css
.sidebar { flex: 0 0 240px; } /* 固定 240px,不放大不缩小 */
.main { flex: 1; } /* 占满剩余空间 */
/* 经典:侧边栏固定 + 主区自适应 */
⑥ align-self ------ 单个项目在交叉轴的对齐
覆盖容器的 align-items,取值相同。
css
.container { align-items: center; }
.item-special { align-self: flex-end; } /* 只把这个项目放到底部 */
Flex 属性速查表:
| 属性 | 作用于 | 常用取值 |
|---|---|---|
flex-direction |
容器 | row / column / ...reverse |
flex-wrap |
容器 | nowrap / wrap |
flex-flow |
容器 | direction + wrap |
justify-content |
容器 | center / space-between / space-evenly |
align-items |
容器 | center / stretch / baseline |
align-content |
容器 | 多行分布 |
gap |
容器 | 间距 |
order |
项目 | 排列顺序 |
flex-grow |
项目 | 放大比例 |
flex-shrink |
项目 | 缩小比例 |
flex-basis |
项目 | 初始尺寸 |
flex |
项目 | 三合一简写 |
align-self |
项目 | 单项目对齐 |
二、CSS Grid 网格布局
2.1 基本概念
Grid 是"二维"布局,同时处理行和列。
css
.container {
display: grid; /* 或 inline-grid */
}
关键概念:
- 网格线(grid line):划分网格的线,行线/列线;
- 网格轨道(track):两条相邻线之间的行/列;
- 网格单元(cell):行与列交叉的最小单位;
- 网格区域(area):一个或多个单元格组成的矩形区域。
makefile
列线: 1 2 3 4
│ 100px │ 1fr │ 1fr │
行线 1┌────────┬────────┬────────┐
│ cell │ cell │ cell │
行线 2├────────┼────────┼────────┤
│ cell │ cell │ cell │
行线 3└────────┴────────┴────────┘
示例:
html
<div class="grid">
<div class="box">A</div>
<div class="box">B</div>
<div class="box">C</div>
<div class="box">D</div>
</div>
css
.grid {
display: grid;
grid-template-columns: 100px 1fr 1fr; /* 3 列:固定 + 两列自适应 */
grid-template-rows: 80px 80px; /* 2 行 */
gap: 12px;
}
.box {
background: #409eff;
color: #fff;
display: grid;
place-items: center; /* 单元格内居中 */
}
2.2 容器属性(写在父元素上)
① grid-template-columns / grid-template-rows ------ 定义轨道
支持多种单位:
css
/* 固定值 */
.grid { grid-template-columns: 100px 200px 100px; }
/* 百分比 */
.grid { grid-template-columns: 25% 25% 50%; }
/* fr(fraction 分数单位):按比例瓜分剩余空间 */
.grid { grid-template-columns: 1fr 2fr 1fr; } /* 1:2:1 三列 */
/* repeat():重复 */
.grid { grid-template-columns: repeat(3, 1fr); } /* 等同 1fr 1fr 1fr */
/* minmax():最小-最大约束 */
.grid { grid-template-columns: minmax(200px, 1fr) 1fr; }
/* 第一列至少 200px,最多占满剩余 */
/* auto:按内容 */
.grid { grid-template-columns: auto 1fr; }
css
/* 行同理 */
.grid {
grid-template-rows: 100px auto 1fr; /* 头 / 内容自适应 / 尾部占满 */
}
auto-fill 与 auto-fit ------ 自动填充:
css
.grid {
display: grid;
/* 每列至少 200px,能放几列放几列(自适应列数) */
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
/* auto-fit 与 auto-fill 区别:项目少时 auto-fit 会把空轨道塌陷合并 */
}
② grid-template-areas ------ 区域命名布局
css
.page {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: 60px 1fr 60px;
grid-template-areas:
"header header"
"sidebar content"
"footer footer";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer { grid-area: footer; }
css
┌──────────┬──────────┐
│ header │ header │
├──────────┼──────────┤
│ sidebar │ content │
├──────────┼──────────┤
│ footer │ footer │
└──────────┴──────────┘
用
.(点)表示空单元格:grid-template-areas: "a . b";
③ gap ------ 行列间距
css
.grid {
display: grid;
gap: 16px; /* 行列统一 */
row-gap: 12px; /* 行间距 */
column-gap: 8px; /* 列间距 */
}
④ grid-auto-flow ------ 项目自动放置规则
| 取值 | 效果 |
|---|---|
row(默认) |
按行依次放置,放满一行换下一行 |
column |
按列依次放置 |
dense |
回填前面留下的空洞(可与 row/column 组合:row dense) |
css
.grid { grid-auto-flow: column; } /* 纵向排列 */
.grid { grid-auto-flow: row dense; } /* 尽量紧凑,回填空洞 */
⑤ grid-auto-rows / grid-auto-columns ------ 隐式轨道大小
显式轨道用 grid-template-* 定义;放不下的项目会创建"隐式轨道",用这组属性控制其大小。
css
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 80px; /* 新增行的默认高度 */
grid-auto-columns: 100px; /* 新增列的默认宽度 */
}
⑥ justify-items / align-items ------ 项目在单元格内的对齐
| 取值 | 效果 |
|---|---|
stretch(默认) |
拉伸填满单元格 |
start |
起点(左/上) |
end |
终点(右/下) |
center |
居中 |
css
.grid {
justify-items: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
/* 简写 */
place-items: center; /* = justify-items + align-items */
}
⑦ justify-content / align-content ------ 整个网格在容器内的对齐
当网格总尺寸小于容器(例如用固定像素定义轨道)时生效。
css
.grid {
display: grid;
grid-template-columns: 100px 100px; /* 总宽 200px < 容器 */
justify-content: center; /* 网格整体水平居中 */
align-content: space-between; /* 网格整体垂直分布 */
/* 简写 */
place-content: center;
}
取值:start / end / center / stretch / space-between / space-around / space-evenly。
⑧ grid-template ------ 简写
css
.grid {
/* grid-template-rows / grid-template-columns / grid-template-areas */
grid-template:
"header header" 60px
"sidebar content" 1fr
"footer footer" 60px
/ 200px 1fr;
}
2.3 项目属性(写在子元素上)
① grid-column / grid-row ------ 按网格线定位
css
.item {
/* 从第 1 列线到第 3 列线(占 2 列) */
grid-column: 1 / 3;
/* 从第 2 行线开始,跨越 2 行 */
grid-row: 2 / span 2;
}
常用写法:
css
.item { grid-column: 1 / 3; } /* 起线 / 止线 */
.item { grid-column: 1 / -1; } /* -1 表示最后一条线,即占满整行 */
.item { grid-column: span 2; } /* 跨越 2 列(不指定起线) */
.item { grid-column: 2; } /* 单列简写 */
.item { grid-column: 1 / span 2; } /* 从线 1 开始跨 2 列 */
示例:一列跨两列:
css
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
.item-wide { grid-column: 1 / 3; } /* 占第 1、2 列 */
② grid-area ------ 区域定位
两种用法:用 grid-template-areas 定义的名字,或四线定位。
css
/* 用法一:区域名(配合 grid-template-areas) */
.item { grid-area: sidebar; }
/* 用法二:四条网格线 row-start / column-start / row-end / column-end */
.item {
grid-area: 1 / 1 / 3 / 3;
/* 从第1行第1列 到 第3行第3列(占 2x2) */
}
③ justify-self / align-self / place-self ------ 单个项目在单元格内对齐
css
.item {
justify-self: center; /* 水平居中(覆盖 justify-items) */
align-self: end; /* 垂直靠下 */
place-self: center; /* 简写,单元格内居中 */
}
Grid 属性速查表:
| 属性 | 作用于 | 作用 |
|---|---|---|
grid-template-columns/rows |
容器 | 定义轨道(fr / repeat / minmax) |
grid-template-areas |
容器 | 区域命名布局 |
gap |
容器 | 行列间距 |
grid-auto-flow |
容器 | 自动放置规则(row/column/dense) |
grid-auto-rows/columns |
容器 | 隐式轨道大小 |
justify/align/place-items |
容器 | 项目在单元格内对齐 |
justify/align/place-content |
容器 | 网格整体对齐 |
grid-column/row |
项目 | 按线定位、跨越 |
grid-area |
项目 | 区域定位 / 四线定位 |
justify/align/place-self |
项目 | 单项目对齐 |
三、Flex vs Grid:对比与选型
3.1 核心区别
| 对比项 | Flex | Grid |
|---|---|---|
| 维度 | 一维(一个方向) | 二维(行 + 列) |
| 设计思想 | 内容驱动(项目伸缩填满) | 布局驱动(先画网格再放内容) |
| 擅长 | 单行/单列排列、对齐、居中等 | 页面骨架、规则二维布局 |
| 跨行跨列 | 不支持(同一轴线) | 原生支持(span / grid-area) |
| 列数 | 由内容决定 | 由轨道定义决定 |
3.2 典型选型建议
优先用 Flex:
css
/* 导航栏:一行水平分布 */
.nav { display: flex; justify-content: space-between; align-items: center; }
/* 按钮组 / 图标行 */
.toolbar { display: flex; gap: 8px; }
/* 垂直居中 */
.center { display: flex; justify-content: center; align-items: center; }
/* 固定侧栏 + 自适应主区 */
.sidebar { flex: 0 0 240px; }
.main { flex: 1; }
优先用 Grid:
css
/* 页面整体骨架:二维区域划分 */
.page {
display: grid;
grid-template-areas:
"header header"
"sidebar content"
"footer footer";
}
/* 商品卡片网格:自动响应式列数 */
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 16px;
}
/* 九宫格 / 表格类布局 */
.board {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 100px;
gap: 8px;
}
3.3 两者混用(最常用实践)
用 Grid 做整体骨架 ,用 Flex 做局部对齐:
css
.page {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-rows: 60px 1fr;
grid-template-areas:
"header header"
"sidebar content";
height: 100vh;
}
.header {
grid-area: header;
display: flex; /* Grid 里再用 Flex */
justify-content: space-between;
align-items: center;
}
.content {
grid-area: content;
display: grid; /* 内容区再嵌套 Grid */
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 12px;
}
3.4 常见面试追问
Q:Flex 和 Grid 能互相替代吗? 不能完全替代。Flex 擅长单维度的弹性排列与对齐;Grid 擅长二维的规则划分。复杂布局常两者组合使用。
Q:flex: 1 和 1fr 的区别?
flex: 1是 flex-grow: 1,针对剩余空间按比例分配;1fr是网格分数单位,针对整条轨道按比例分配。 两者都能实现自适应,但作用模型不同。
Q:什么时候用 place-items 什么时候用 place-content?
place-items控制项目在单元格内的位置;place-content控制整个网格在容器中的位置。
收藏这份指南,配合动手敲代码练习:先掌握 Flex 的一维思维,再掌握 Grid 的二维思维,两者结合基本能覆盖前端 99% 的布局场景。