如果说现代 CSS 布局最重要的两套工具是什么,答案基本就是:
flexgrid很多人知道:
flex 很常用grid 很强大但真正写项目时,还是会遇到很多问题:
flex: 1 有时候不生效?grid 明明写了三列,结果列宽不对?gap 有时很好用,有时看起来又像没效果?overflow、ellipsis、height: 100% 结果怪怪的?这篇文章不只讲语法,而是把 Flex / Grid 的核心思路、详细使用、常见问题、注意事项 一次讲透。
一、先说结论:什么时候用 Flex,什么时候用 Grid
先记住最实用的一句话:
什么叫一维布局?
就是你主要只关心一个方向:
典型场景:
这类优先用 flex。
什么叫二维布局?
就是你同时要关心:
典型场景:
这类优先用 grid。
一句更贴近项目的话:
flex 是一种 弹性盒布局(Flexible Box Layout)。
它的核心思想是:
让父元素控制子元素如何沿一个方向排列、对齐、伸缩。
也就是说:
flex 主要是给父元素用的display: flexflex itemsflex 算法决定例如:
css 体验AI代码助手 代码解读复制代码.container {
display: flex;
}这句话的意思不是“让这个容器自己变横着”,而是:
让这个容器里面的子元素按 flex 规则布局。
要真正用好 flex,先把这几个概念吃透。
写了:
css 体验AI代码助手 代码解读复制代码.container {
display: flex;
}这个 .container 就是 Flex 容器。
Flex 容器的直接子元素,就是 Flex 项。
例如:
ini 体验AI代码助手 代码解读复制代码<div class="container">
<div class="item">A</div>
<div class="item">B</div>
<div class="item">C</div>
</div>这里:
.container 是 flex container.item 是 flex items注意:
只有直接子元素才是 flex item。 孙元素不会自动成为 flex item。
Flex 布局里,最重要的是“轴”的概念。
主轴默认是横向。
也就是默认情况下,子元素从左到右排。
css 体验AI代码助手 代码解读复制代码.container {
display: flex;
flex-direction: row;
}这是默认值。
和主轴垂直的方向,就是交叉轴。
如果主轴是横向:
如果主轴改成纵向:
css 体验AI代码助手 代码解读复制代码.container {
display: flex;
flex-direction: column;
}那就变成:
Flex 常见对齐问题,本质都在这两个点:
justify-content:控制主轴对齐align-items:控制交叉轴对齐这个一定要记牢。
display: flex开启 flex 布局。
css 体验AI代码助手 代码解读复制代码.container {
display: flex;
}默认效果:
flex-direction控制主轴方向。
css 体验AI代码助手 代码解读复制代码.container {
flex-direction: row;
}可选值:
row:横向,从左到右row-reverse:横向,从右到左column:纵向,从上到下column-reverse:纵向,从下到上示例:
css 体验AI代码助手 代码解读复制代码.container {
display: flex;
flex-direction: column;
}这时子元素会竖着排。
justify-content控制主轴对齐。
常见值:
flex-startcenterflex-endspace-betweenspace-aroundspace-evenly示例:
css 体验AI代码助手 代码解读复制代码.container {
display: flex;
justify-content: center;
}如果主轴是横向,表示水平居中。
css 体验AI代码助手 代码解读复制代码.container {
display: flex;
justify-content: space-between;
}表示两端对齐,中间均匀分开。
align-items控制交叉轴对齐。
常见值:
stretch(默认)flex-startcenterflex-endbaseline示例:
css 体验AI代码助手 代码解读复制代码.container {
display: flex;
align-items: center;
}如果主轴是横向,这通常表示垂直居中。
flex-wrap控制是否换行。
默认:
css 体验AI代码助手 代码解读复制代码flex-wrap: nowrap;也就是不换行。
可选值:
nowrapwrapwrap-reverse示例:
css 体验AI代码助手 代码解读复制代码.container {
display: flex;
flex-wrap: wrap;
}当子元素放不下时,会自动换到下一行。
gap控制 flex 项之间的间距。
css 体验AI代码助手 代码解读复制代码.container {
display: flex;
gap: 16px;
}这通常比给子元素写 margin-right 更干净。
优点:
align-content这个属性很容易和 align-items 混。
它的作用是:
当 flex items 出现多行时,控制多行整体在交叉轴上的分布。
也就是说:
align-content 通常没意义flex-grow控制子元素如何分配剩余空间。
css 体验AI代码助手 代码解读复制代码.item {
flex-grow: 1;
}意思是:
例子:
css 体验AI代码助手 代码解读复制代码.item1 {
flex-grow: 1;
}
.item2 {
flex-grow: 2;
}那么剩余空间会按 1:2 分。
flex-shrink控制空间不够时,子元素怎么缩小。
默认:
css 体验AI代码助手 代码解读复制代码flex-shrink: 1;意思是默认允许缩小。
如果不想缩小:
css 体验AI代码助手 代码解读复制代码.item {
flex-shrink: 0;
}这在某些固定宽度按钮、图标、头像中很常见。
flex-basis定义子元素在主轴方向上的基础尺寸。
css 体验AI代码助手 代码解读复制代码.item {
flex-basis: 200px;
}它比直接写 width 更符合 flex 的思维。
因为它表示:
在 flex 算法开始分配空间前,这个项目的“初始参考尺寸”。
flex 简写这是最常见的写法之一。
css 体验AI代码助手 代码解读复制代码.item {
flex: 1;
}它通常可以理解为:
css 体验AI代码助手 代码解读复制代码flex-grow: 1;
flex-shrink: 1;
flex-basis: 0%;这表示:
常见几种写法:
css 体验AI代码助手 代码解读复制代码flex: 1;
flex: auto;
flex: none;
flex: 0 0 200px;其中最常见的是:
flex: 1常用于多个子元素平分空间。
flex: 0 0 200px表示:
适合固定列宽、固定按钮宽度等场景。
align-self让某个子元素单独覆盖 align-items。
css 体验AI代码助手 代码解读复制代码.item {
align-self: flex-start;
}适合个别元素单独调整。
css 体验AI代码助手 代码解读复制代码.container {
display: flex;
justify-content: center;
align-items: center;
}这是最经典的 flex 场景。
css 体验AI代码助手 代码解读复制代码.header {
display: flex;
justify-content: space-between;
align-items: center;
}适合:
css 体验AI代码助手 代码解读复制代码.actions {
display: flex;
gap: 12px;
}css 体验AI代码助手 代码解读复制代码.container {
display: flex;
}
.sidebar {
width: 240px;
flex-shrink: 0;
}
.content {
flex: 1;
}非常常见。
css 体验AI代码助手 代码解读复制代码.list {
display: flex;
flex-wrap: wrap;
gap: 16px;
}如果只是简单“换行排卡片”,flex 也能做。
但如果你明确是多行多列网格,通常 grid 更自然。
css 体验AI代码助手 代码解读复制代码.container {
display: flex;
}
.right {
margin-left: auto;
}这是 flex 很经典的用法。
这一部分是最重要的实战部分。
flex: 1 有时候不生效?最常见原因有几个:
只有父元素是 display: flex,它的直接子元素上写 flex: 1 才有意义。
flex-grow 是分“剩余空间”的。
如果本来就没空间,当然看不出效果。
某些内容过长,默认最小尺寸限制会让元素没法按预期收缩或分配。
这时常见解决方式是:
arduino 体验AI代码助手 代码解读复制代码.item {
min-width: 0;
}这个点非常重要。
这是 flex 最经典的坑之一。
例如:
css 体验AI代码助手 代码解读复制代码.container {
display: flex;
}
.left {
width: 100px;
}
.right {
flex: 1;
}.right 里面如果有一段特别长、不能换行的文字,布局可能会被撑爆。
原因通常不是 flex 坏了,而是:
flex item 默认的最小尺寸限制,不允许它比内容最小尺寸更小。
解决办法通常是:
css 体验AI代码助手 代码解读复制代码.right {
flex: 1;
min-width: 0;
}如果是纵向 flex 布局,类似问题则常常要写:
arduino 体验AI代码助手 代码解读复制代码.child {
min-height: 0;
}这个是实战必记点。
ellipsis 在 flex 里不生效?你明明写了:
css 体验AI代码助手 代码解读复制代码.title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}但还是不生效,常见原因是 flex item 没有被允许缩小。
解决方式很常见是:
css 体验AI代码助手 代码解读复制代码.title-wrap {
flex: 1;
min-width: 0;
}然后内部文本再做省略。
因为 align-items 默认值是:
css 体验AI代码助手 代码解读复制代码align-items: stretch;这意味着在交叉轴方向上,子元素可能被自动拉伸。
如果不想这样,可以改成:
css 体验AI代码助手 代码解读复制代码.container {
align-items: flex-start;
}或者:
css 体验AI代码助手 代码解读复制代码.container {
align-items: center;
}margin-top: auto / margin-left: auto 在 flex 里特别强?因为在 flex 布局里,auto margin 可以吸收剩余空间。
比如:
css 体验AI代码助手 代码解读复制代码.item {
margin-left: auto;
}就能把自己推到最右边。
在纵向 flex 布局里:
css 体验AI代码助手 代码解读复制代码.item {
margin-top: auto;
}可以把元素推到底部。
这个比很多定位写法更优雅。
width 和 flex-basis 看起来像打架?在 flex item 上:
flex-basis 是 flex 算法的初始参考尺寸width 是普通盒模型尺寸属性如果两者都写,实际布局常常以 flex 规则为主。
项目里建议:
flex-basiswidth,一边又写复杂的 flex经典场景:
css 体验AI代码助手 代码解读复制代码.page {
display: flex;
flex-direction: column;
height: 100vh;
}
.main {
flex: 1;
overflow: auto;
}结果 .main 不能正常滚。
很多时候要补:
css 体验AI代码助手 代码解读复制代码.main {
flex: 1;
min-height: 0;
overflow: auto;
}原因和前面一样: flex item 默认最小尺寸限制会影响收缩。
这个在页面布局里极其常见。
虽然 flex + wrap 也能排多行卡片,但如果你明确要:
那应该优先考虑 grid。
grid 是 网格布局(CSS Grid Layout) 。
它的核心思想是:
父元素先定义一个二维网格,然后子元素按网格的行和列进行布局。
和 flex 最大的区别在于:
flex 更擅长一维grid 更擅长二维示例:
css 体验AI代码助手 代码解读复制代码.container {
display: grid;
}一旦开启 grid,子元素就会作为 grid items 按网格规则布局。
写了:
css 体验AI代码助手 代码解读复制代码.container {
display: grid;
}这个元素就是 grid container。
它的直接子元素就是 grid items。
Grid 最核心的概念之一是轨道。
轨道就是:
例如:
css 体验AI代码助手 代码解读复制代码.container {
display: grid;
grid-template-columns: 200px 1fr 1fr;
}表示三列:
每一行每一列之间都有线,用来定义项目开始和结束位置。
行和列交叉出的格子,就是单元格。
多个单元格可以组成一个区域。
这使得 Grid 非常适合做页面骨架布局。
display: grid开启 grid 布局。
css 体验AI代码助手 代码解读复制代码.container {
display: grid;
}grid-template-columns定义列轨道。
css 体验AI代码助手 代码解读复制代码.container {
display: grid;
grid-template-columns: 200px 1fr 1fr;
}常见写法:
css 体验AI代码助手 代码解读复制代码grid-template-columns: repeat(3, 1fr);表示三列,每列平分空间。
grid-template-rows定义行轨道。
arduino 体验AI代码助手 代码解读复制代码.container {
grid-template-rows: 60px auto 40px;
}gap定义网格间距。
css 体验AI代码助手 代码解读复制代码.container {
display: grid;
gap: 16px;
}也可以分开写:
css 体验AI代码助手 代码解读复制代码row-gap: 16px;
column-gap: 24px;repeat()重复写法,非常常用。
css 体验AI代码助手 代码解读复制代码grid-template-columns: repeat(4, 1fr);比手写 1fr 1fr 1fr 1fr 更简洁。
fr 单位fr 表示剩余空间的比例单位。
css 体验AI代码助手 代码解读复制代码grid-template-columns: 1fr 2fr 1fr;表示三列按 1:2:1 分剩余空间。
minmax()定义最小值和最大值范围。
css 体验AI代码助手 代码解读复制代码grid-template-columns: repeat(3, minmax(200px, 1fr));意思是:
这是响应式网格里非常强大的工具。
auto-fit / auto-fill这是 Grid 响应式卡片布局的经典写法。
css 体验AI代码助手 代码解读复制代码.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;
}效果通常是:
这是非常推荐掌握的写法。
grid-column / grid-row控制某个项目跨几列、跨几行。
css 体验AI代码助手 代码解读复制代码.item {
grid-column: 1 / 3;
}表示从第 1 根列线到第 3 根列线,也就是横跨 2 列。
css 体验AI代码助手 代码解读复制代码.item {
grid-row: 1 / 3;
}表示跨 2 行。
grid-template-areas给网格区域命名。
css 体验AI代码助手 代码解读复制代码.container {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-areas:
"sidebar header"
"sidebar main";
}子元素:
css 体验AI代码助手 代码解读复制代码.sidebar {
grid-area: sidebar;
}
.header {
grid-area: header;
}
.main {
grid-area: main;
}这对页面骨架布局很清晰。
justify-items / align-items控制 grid item 在单元格里的对齐方式。
css 体验AI代码助手 代码解读复制代码.container {
justify-items: center;
align-items: center;
}justify-content / align-content控制整个网格在容器中的分布。
这一组容易和 items 混。
可以这样记:
*-items:控制每个格子里的项目*-content:控制整个网格整体css 体验AI代码助手 代码解读复制代码.list {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
}css 体验AI代码助手 代码解读复制代码.list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 16px;
}这是很推荐的现代写法。
css 体验AI代码助手 代码解读复制代码.layout {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-rows: 64px 1fr;
grid-template-areas:
"sidebar header"
"sidebar main";
height: 100vh;
}
.sidebar {
grid-area: sidebar;
}
.header {
grid-area: header;
}
.main {
grid-area: main;
}css 体验AI代码助手 代码解读复制代码.featured {
grid-column: span 2;
grid-row: span 2;
}适合做精选卡片、推荐块。
1fr 有时候会被内容撑爆?这是 Grid 的经典坑。
例如:
css 体验AI代码助手 代码解读复制代码.container {
display: grid;
grid-template-columns: 200px 1fr;
}右边列里如果有长内容,有时会把网格撑开。
因为 1fr 轨道不总是你想象中的“无脑自适应”,它仍然会受内容最小尺寸影响。
一个很常见的解决方式是:
css 体验AI代码助手 代码解读复制代码grid-template-columns: 200px minmax(0, 1fr);这个非常重要。
你会发现:
minmax(0, 1fr) 在很多实战里比直接 1fr 更稳原因和 flex 很像: 默认最小尺寸限制导致项目无法缩小到触发省略。
常见解决方式:
arduino 体验AI代码助手 代码解读复制代码.item {
min-width: 0;
}或者轨道上直接用:
css 体验AI代码助手 代码解读复制代码grid-template-columns: minmax(0, 1fr);auto-fit 和 auto-fill 有什么区别?这是 Grid 最常见的疑问之一。
可以先用最直观方式理解:
auto-fill:尽可能“填充”更多轨道,即使有的轨道可能空着auto-fit:更倾向把已有项目拉伸去占满空间在实际卡片响应式布局中:
大多数时候你更想用
auto-fit
因为视觉上更自然。
grid-template-areas 很好看,但有时不灵活?它非常适合:
但如果项目数量动态变化很多,或者布局高度不规则,可能就不如直接写列规则灵活。
所以不要什么都上 areas。
Grid 很强,但不是所有场景都该用 Grid。
例如:
这类通常 Flex 更自然。
你写卡片网格时,经常会遇到:
这时要想清楚你要的是:
如果要统一高度,通常还需要对卡片内部再配合 flex。
这也是 Grid 和 Flex 经常组合使用的原因。
Grid 负责:
Flex 负责:
这是非常典型的实战组合。
实际项目里,最常见的不是二选一,而是配合用。
例如:
例如:
例如:
css 体验AI代码助手 代码解读复制代码.card-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 16px;
}
.card {
display: flex;
flex-direction: column;
}这样:
这是非常现代、非常推荐的写法。
对比项 | Flex | Grid |
|---|---|---|
维度 | 一维 | 二维 |
更适合 | 一行/一列排列 | 多行多列网格 |
主体思路 | 沿主轴分配与对齐 | 定义行列轨道 |
典型场景 | 导航、按钮组、居中、工具栏 | 卡片墙、后台布局、页面骨架 |
常见坑 | min-width: 0、伸缩、溢出 | minmax(0, 1fr)、内容撑爆、区域规划 |
最佳搭档 | Grid | Flex |
如果要把 Flex 和 Grid 真正用顺,最重要的不是死背属性,而是建立这两个思维:
父容器控制子元素沿一个方向如何排列、对齐、伸缩。
父容器先定义二维网格,再让子元素落入网格。
最后再压缩成最实用的开发建议:
min-width: 0 / min-height: 0minmax(0, 1fr)原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。