Flex 与 Grid 使用技巧 & 注意点
一份面向实战的 CSS 布局速查 —— 何时用 Flex、何时用 Grid、常见坑与最佳实践
一、心智模型:先选对工具
| 维度 |
Flexbox |
Grid |
| 维度 |
一维(行 或 列) |
二维(行 和 列) |
| 思路 |
内容驱动(让子项自适应) |
布局驱动(先画格子,再放内容) |
| 典型场景 |
导航栏、按钮组、卡片内部、表单行 |
页面级布局、仪表盘、瀑布流、复杂表格 |
| 子项控制权 |
子项 (flex-grow/shrink/basis) |
容器 (grid-template-*) |
一句话决策:
- 一行/一列排列 → Flex
- 同时要管行又管列 → Grid
- 复杂卡片:外层 Grid + 内层 Flex(最常见组合)
二、Flexbox 实战技巧
1. 常用容器属性速查
.container {
display: flex; /* 或 inline-flex */
flex-direction: row | column; /* 主轴方向 */
flex-wrap: wrap; /* 默认 nowrap,移动端必加 */
justify-content: space-between; /* 主轴对齐 */
align-items: center; /* 交叉轴对齐(单行) */
align-content: center; /* 交叉轴对齐(多行) */
gap: 12px 8px; /* 行间距 列间距 */
}
2. 子项控制三件套
.item {
flex: 1 1 auto;
/* ↑ 等价于:flex-grow flex-shrink flex-basis */
}
| 简写 |
等价 |
用途 |
flex: 1 |
1 1 0% |
平均分配剩余空间(最常用) |
flex: auto |
1 1 auto |
按内容大小分配 |
flex: none |
0 0 auto |
不伸不缩(固定宽度侧边栏) |
flex: 0 0 200px |
— |
固定 200px 宽 |
3. 经典模式
/* ✅ 圣杯布局:左侧栏固定 + 右侧自适应 */
.layout {
display: flex;
}
.sidebar {
flex: 0 0 240px;
}
.main {
flex: 1;
min-width: 0;
} /* min-width: 0 关键! */
/* ✅ 垂直水平居中(一行搞定) */
.center {
display: flex;
justify-content: center;
align-items: center;
}
/* ✅ 等高卡片 */
.cards {
display: flex;
} /* 默认 align-items: stretch */
/* ✅ 底部对齐按钮 */
.card {
display: flex;
flex-direction: column;
}
.card-footer {
margin-top: auto;
} /* 神技 */
4. ⚠️ Flex 高频坑
| 坑 |
现象 |
解法 |
| 文字溢出撑破容器 |
子项有长文本时 flex: 1 撑爆 |
子项加 min-width: 0(或 overflow: hidden) |
| flex-basis vs width |
同时设置时优先级混乱 |
用 flex-basis 别用 width(更语义化) |
| gap 兼容性 |
老 Safari 不支持 |
降级用 margin 或加 :not(:last-child) |
| flex-shrink 默认 1 |
图片被压缩变形 |
img { flex-shrink: 0; } |
| align-items: stretch 撑高图片 |
img 被拉伸 |
父级 align-items: flex-start 或 img 包一层 div |
| 百分比 margin |
Flex 容器中 margin-top: 50% 不基于父高 |
用 transform 或绝对定位 |
5. 高级技巧
/* margin: auto 在 Flex 中是"占据剩余空间" */
.nav-right {
margin-left: auto;
} /* 推到最右边,不用 justify-content */
/* 反向排列但保留 tab 顺序 */
.reverse {
flex-direction: row-reverse;
}
/* order 重排(不影响 DOM 顺序,无障碍友好) */
.first {
order: -1;
}
三、Grid 实战技巧
1. 容器属性速查
.grid {
display: grid;
grid-template-columns: 200px 1fr 1fr; /* 3 列 */
grid-template-rows: auto 1fr auto; /* 3 行 */
gap: 16px; /* 等于 row-gap + column-gap */
/* 命名区域(最强可读性) */
grid-template-areas:
"header header header"
"side main main"
"footer footer footer";
}
2. 必学单位与函数
| 工具 |
用途 |
示例 |
fr |
分配剩余空间 |
1fr 2fr 1fr |
minmax(min, max) |
限制范围 |
minmax(200px, 1fr) |
repeat() |
重复 |
repeat(3, 1fr) |
auto-fill |
自动填满,保留空轨道 |
repeat(auto-fill, minmax(200px, 1fr)) |
auto-fit |
自动填满,折叠空轨道 |
卡片少时撑满整行 |
3. 神级一行:响应式卡片网格
/* 屏幕宽自动放 N 列,每列至少 240px */
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 16px;
}
/* 不需要任何媒体查询! */
4. 子项定位
/* 方式 1:行列线 */
.item {
grid-column: 1 / 3; /* 从第 1 条线到第 3 条线 */
grid-row: 2 / span 2; /* 跨 2 行 */
}
/* 方式 2:命名区域(推荐) */
.header {
grid-area: header;
}
.main {
grid-area: main;
}
/* 方式 3:负数索引(从末尾算) */
.last {
grid-column: -2 / -1;
}
5. 对齐三件套(Grid 比 Flex 更强)
/* 容器层 */
justify-items: center; /* 子项在格子内水平对齐 */
align-items: center; /* 子项在格子内垂直对齐 */
place-items: center; /* 上面两个的简写 */
justify-content: center; /* 整个网格在容器内水平对齐 */
align-content: center; /* 整个网格在容器内垂直对齐 */
place-content: center;
/* 子项层(可单独覆盖) */
.item {
justify-self: end;
align-self: start;
}
6. 经典模式
/* ✅ 圣杯布局(命名区域版,秒懂) */
.layout {
display: grid;
grid-template:
"header header" auto
"side main" 1fr
"footer footer" auto
/ 240px 1fr;
}
/* ✅ 表单:左侧 label 右侧 input 自动对齐 */
.form {
display: grid;
grid-template-columns: auto 1fr;
gap: 12px;
align-items: center;
}
/* ✅ 子项重叠(Grid 独有!) */
.stack > * {
grid-area: 1 / 1;
} /* 全部叠在同一格 */
7. ⚠️ Grid 高频坑
| 坑 |
现象 |
解法 |
| 隐式行高失控 |
没设 grid-template-rows,行高被内容撑爆 |
显式定义 grid-auto-rows: minmax(100px, auto) |
| fr 与 content 冲突 |
1fr 列被超长文本撑大 |
minmax(0, 1fr) 替代 1fr |
| subgrid 兼容性 |
老浏览器不支持 |
Firefox 全支持,Chrome 117+,按需降级 |
| gap 计入 fr 计算 |
算出来的列宽和预期不符 |
gap 是从总宽度先扣除再分配 |
| auto-fill vs auto-fit |
空轨道是否塌缩 |
卡片少又想撑满 → auto-fit;保留占位 → auto-fill |
| z-index 失效 |
Grid 子项需要 position: relative |
加上即可 |
四、Flex vs Grid 对比决策表
| 需求 |
推荐 |
原因 |
| 导航栏 |
Flex |
一维排列,需要 margin-left: auto |
| 按钮组 |
Flex |
gap + align-items 够用 |
| 卡片列表(自适应列数) |
Grid |
auto-fill + minmax 无媒体查询 |
| 仪表盘 |
Grid |
二维布局,命名区域可读性强 |
| 表单(label + input) |
Grid |
auto 1fr 自动对齐 |
| 元素重叠(如徽章) |
Grid |
grid-area: 1/1 比绝对定位优雅 |
| 聊天气泡 |
Flex |
一列,按 align-self 左右切换 |
| 后台 Layout(顶部+侧栏+主内容) |
Grid |
一次性画清结构 |
| 居中 |
Flex |
三行代码秒中 |
五、组合使用范式(实战标配)
<!-- 外层 Grid 管页面 → 内层 Flex 管组件 -->
<div class="page">
<!-- Grid -->
<header class="navbar"><!-- Flex --></header>
<aside class="sidebar"></aside>
<main class="content">
<!-- Grid 卡片墙 -->
<article class="card"><!-- Flex 列 --></article>
</main>
</div>
.page {
display: grid;
grid-template: "nav nav" auto "side main" 1fr / 240px 1fr;
min-height: 100vh;
}
.navbar {
display: flex;
align-items: center;
justify-content: space-between;
}
.content {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 16px;
}
.card {
display: flex;
flex-direction: column;
}
.card-footer {
margin-top: auto;
}
六、性能与可维护性建议
- 优先用现代特性:
gap 替代 margin 间距;place-items 替代多行对齐
- 响应式优先 Grid:
auto-fill + minmax 比媒体查询断点更优雅
- 避免过度嵌套 Flex:超过 3 层考虑换 Grid
min-width: 0 / min-height: 0 是 Flex/Grid 子项的"隐藏开关",记牢
- 命名区域 > 行列线数字:可读性、可维护性碾压
- Subgrid(Chrome 117+)让嵌套 Grid 对齐父网格,复杂表单/表格神器
- 避免动画
width/height:用 transform: scale(),Flex/Grid 重排成本高
- DevTools 用起来:Chrome 的 Grid/Flex Overlay 可视化调试
七、速记
Flex 一维、Grid 二维;Flex 内容驱动、Grid 布局驱动;
导航栏卡片内部用 Flex,页面级布局和卡片墙用 Grid;
gap 是新时代的 margin;min-width: 0 是 Flex 子项的救命符;
repeat(auto-fill, minmax(240px, 1fr)) 是响应式神咒;
外层 Grid + 内层 Flex 是中后台最常见组合。
八、参考资源