在 CSS 布局的发展历程中,Flex 布局(弹性布局)的出现彻底改变了传统布局的繁琐 —— 它告别了依赖
float
、position
的 hack 式写法,以直观的 “弹性” 思维实现元素的对齐、分布与自适应,成为现代前端开发中最常用的布局方案之一。本文将从核心概念到实战案例,带你系统掌握 Flex 布局的所有关键知识点。
一、什么是 Flex 布局?
Flex(Flexible Box,弹性盒)是 CSS3 引入的一种一维布局模型—— 它通过定义 “容器” 和 “项目” 的关系,控制项目在 “主轴” 和 “交叉轴” 上的排列方式,实现灵活的空间分配与对齐。
相比传统布局,Flex 的核心优势在于:
- 简化对齐:轻松实现水平 / 垂直居中、两端对齐等常见需求;
- 自适应强:自动分配剩余空间或收缩项目,适配不同屏幕尺寸;
- 摆脱 hack:无需清除浮动、避免 margin 塌陷,逻辑更直观。
二、Flex 布局的核心概念:容器与项目
Flex 布局的所有规则都围绕 “容器” 和 “项目” 展开,先明确这两个概念是学习的前提。
1. 容器(Flex Container)
需要开启 Flex 布局的父元素,通过设置display: flex
或display: inline-flex
将其定义为 Flex 容器。
display: flex
:容器为块级元素(独占一行,可设置宽高);display: inline-flex
:容器为行内块元素(宽度由内容决定,与其他行内元素同行排列)。
注意:一旦元素成为 Flex 容器,其内部的子元素(项目)将默认脱离文档流,容器的float
、clear
、vertical-align
属性会失效。
2. 项目(Flex Item)
Flex 容器的直接子元素就是 Flex 项目(间接子元素不生效)。例如:
<div class="container"> <!-- Flex容器 -->
<div class="item">1</div> <!-- Flex项目 -->
<div class="item">2</div> <!-- Flex项目 -->
<div class="item">3</div> <!-- Flex项目 -->
</div>
3. 两大轴:主轴与交叉轴
Flex 布局的核心是 “轴” 的概念 —— 所有项目的排列、对齐都围绕主轴(Main Axis) 和交叉轴(Cross Axis) 展开,两轴始终垂直。
轴的类型 | 定义 | 方向控制 |
---|---|---|
主轴 | 项目的主要排列方向(默认水平从左到右) | 由容器的flex-direction 属性控制 |
交叉轴 | 垂直于主轴的方向(默认垂直从上到下) | 随主轴方向自动变化 |
例如:
- 当主轴为 “水平方向” 时,交叉轴为 “垂直方向”;
- 当主轴为 “垂直方向” 时,交叉轴为 “水平方向”。
三、Flex 容器的 6 个核心属性
Flex 容器通过 6 个属性控制项目的整体排列规则,是 Flex 布局的重点。
1. flex-direction
:控制主轴方向(核心)
决定主轴的方向,直接影响项目的排列方向。
取值 | 主轴方向 | 项目排列效果 |
---|---|---|
row (默认) | 水平从左到右 | 项目从左往右排列 |
row-reverse | 水平从右到左 | 项目从右往左排列 |
column | 垂直从上到下 | 项目从上往下排列 |
column-reverse | 垂直从下到上 | 项目从下往上排列 |
示例
<template>
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</template>
<script setup lang="ts"></script>
<style>
.container {
display: flex;
flex-direction: column; /* 主轴垂直,项目从上到下排 */
height: 300px; /* 给容器高度,方便观察垂直排列 */
border: 1px solid #000;
}
.item {
width: 100px;
height: 50px;
background: #4285f4;
color: white;
margin: 5px;
}
</style>
2. flex-wrap
:控制项目是否换行
默认情况下,项目会在主轴上 “挤在一起不换行”(即使超出容器宽度),flex-wrap
用于控制项目溢出时是否换行。
取值 | 效果 |
---|---|
nowrap (默认) | 不换行,项目可能溢出容器 |
wrap | 换行,溢出的项目向下排列(沿交叉轴正方向) |
wrap-reverse | 换行,溢出的项目向上排列(沿交叉轴反方向) |
代码示例(容器宽度 300px,3 个项目各 100px,默认不换行时刚好排下;若项目各 120px,wrap
会让第 3 个项目换行):
3. flex-flow
:flex-direction
+ flex-wrap
简写
为简化代码,flex-flow
是flex-direction
和flex-wrap
的复合属性,语法:
flex-flow: <flex-direction> <flex-wrap>;
示例:
.container {
display: flex;
flex-flow: row wrap;
width: 300px;
border: 1px solid #000;
}
常用示例:
flex-flow: row wrap;
(水平排列 + 溢出换行,最常用)flex-flow: column nowrap;
(垂直排列 + 不换行)
4. justify-content
:主轴对齐方式(高频)
控制项目在主轴上的对齐方式,是实现 “水平居中”“两端对齐” 等需求的核心属性
取值 | 对齐效果(以主轴水平为例) |
---|---|
flex-start (默认) | 项目靠主轴起点对齐(左对齐) |
flex-end | 项目靠主轴终点对齐(右对齐) |
center | 项目在主轴居中对齐(水平居中) |
space-between | 两端对齐:项目间距相等,首尾项目贴容器边缘 |
space-around | 项目两侧间距相等:项目间间距 = 项目与容器边缘间距 × 2 |
space-evenly | 所有间距相等:项目间间距 = 项目与容器边缘间距 |
代码示例(实现水平居中):
<template>
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</template>
<script setup lang="ts"></script>
<style>
.container {
display: flex;
width: 700px;
justify-content: center; /* 主轴居中 */
border: 1px solid #000;
}
.item {
width: 120px; /* 3*120=360 > 300,会换行 */
height: 50px;
background: #ea4335;
color: white;
margin: 5px;
}
</style>
效果:
5. align-items
:交叉轴对齐方式(单行项目)
控制项目在交叉轴上的对齐方式,仅作用于 “单行项目”(即flex-wrap: nowrap
时)。
取值 | 对齐效果(以交叉轴垂直为例) |
---|---|
stretch (默认) | 项目未设高度时,拉伸至与容器等高 |
flex-start | 项目靠交叉轴起点对齐(上对齐) |
flex-end | 项目靠交叉轴终点对齐(下对齐) |
center | 项目在交叉轴居中对齐(垂直居中) |
baseline | 项目按文字基线对齐(而非项目本身对齐) |
关键区别:
stretch
:依赖项目无固定高度(或高度为auto
);baseline
:若项目文字大小不同,会按文字的基线(底部对齐线)排列,而非项目底部对齐。
代码示例(实现水平 + 垂直居中):
<template>
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</template>
<script setup lang="ts"></script>
<style>
.container {
display: flex;
width: 400px;
height: 200px; /* 容器必须有高度,交叉轴对齐才可见 */
justify-content: center; /* 主轴居中(水平) */
align-items: center; /* 交叉轴居中(垂直) */
border: 1px solid #000;
}
.item {
width: 120px; /* 3*120=360 > 300,会换行 */
height: 50px;
background: #ea4335;
color: white;
margin: 5px;
}
</style>
6. align-content
:交叉轴对齐方式(多行项目)
控制多行项目在交叉轴上的对齐方式,仅作用于 “换行后的多行项目”(即flex-wrap: wrap
或wrap-reverse
时)。若项目只有一行,该属性无效。
取值 | 对齐效果(以交叉轴垂直为例) |
---|---|
stretch (默认) | 多行项目拉伸至填满容器交叉轴高度 |
flex-start | 多行项目靠交叉轴起点对齐(上对齐) |
flex-end | 多行项目靠交叉轴终点对齐(下对齐) |
center | 多行项目在交叉轴居中对齐(垂直居中) |
space-between | 多行两端对齐:行间距相等,首尾行贴容器边缘 |
space-around | 多行两侧间距相等:行间距 = 行与容器边缘间距 × 2 |
注意:align-content
与align-items
的核心区别是 “作用范围”—— 前者管 “多行整体”,后者管 “单行内的项目”。
四、Flex 项目的 6 个核心属性
项目的属性用于控制单个项目的排列规则,可覆盖容器的部分设置(如align-self
覆盖align-items
)。
1. order
:控制项目的排列顺序
默认情况下,项目按 HTML 书写顺序排列(order: 0
)。通过order
可自定义顺序,数值越小,排列越靠前,支持负数。
代码示例:
<template>
<div class="container">
<div class="item1"></div>
<div class="item2"></div>
<div class="item3"></div>
</div>
</template>
<script setup lang="ts"></script>
<style>
.container {
display: flex;
}
.item1 {
order: 2;
width: 100px;
height: 100px;
/* 红色*/
background-color: rgb(255, 209, 209);
} /* 排第3位 */
.item2 {
order: -1;
width: 100px;
height: 100px;
/* 绿色 */
background-color: rgb(209, 255, 227);
} /* 排第1位(负数最小) */
.item3 {
order: 1;
width: 100px;
height: 100px;
/* 紫色 */
background-color: rgb(214, 209, 255);
} /* 排第2位 */
</style>
显示效果
2. flex-grow
:控制项目的放大比例
当容器有剩余空间时,flex-grow
定义项目的 “放大比例”,默认值为0
(即不放大)。
- 若所有项目的
flex-grow
总和为N
,则每个项目分得的剩余空间比例为:自身flex-grow / N
; - 若某项目
flex-grow: 0
,则无论剩余空间多少,它都不放大。
代码示例(容器宽度 400px,3 个项目各 100px,剩余空间 100px):
<template>
<div class="container">
<div class="item item1"></div>
<div class="item item2"></div>
<div class="item item3"></div>
</div>
</template>
<script setup lang="ts"></script>
<style>
.container {
display: flex;
width: 400px;
}
.item {
width: 100px;
height: 50px;
}
.item1 {
background-color: rgb(249, 210, 210);
flex-grow: 1;
} /* 占剩余空间1/(1+2) = 1/3 ≈33px,最终宽度133px */
.item2 {
background-color: rgb(210, 249, 216);
flex-grow: 2;
} /* 占剩余空间2/3 ≈67px,最终宽度167px */
.item3 {
background-color: rgb(216, 210, 249);
flex-grow: 0;
} /* 不放大,宽度保持100px */
</style>
展示效果
3. flex-shrink
:控制项目的缩小比例
当容器空间不足时,flex-shrink
定义项目的 “缩小比例”,默认值为1
(即允许缩小)。
- 若所有项目的
flex-shrink
总和为M
,则每个项目缩小的幅度比例为:(自身宽度 × 自身flex-shrink) / 所有项目(宽度×flex-shrink)总和
; - 若某项目
flex-shrink: 0
,则无论空间是否不足,它都不缩小(可能导致溢出)。
代码示例(容器宽度 300px,3 个项目各 120px,总宽度 360px,需缩小 60px):
<template>
<div class="container">
<div class="item item1"></div>
<div class="item item2"></div>
<div class="item item3"></div>
</div>
</template>
<script setup lang="ts"></script>
<style>
.container {
display: flex;
width: 300px;
}
.item {
width: 120px;
height: 50px;
}
.item1 {
background-color: rgb(249, 210, 210);
flex-shrink: 1;
} /* 缩小幅度:(120×1)/(120×1+120×2+120×0) ×60 = 20px,最终宽度100px */
.item2 {
background-color: rgb(210, 249, 216);
flex-shrink: 2;
} /* 缩小幅度:(120×2)/360 ×60 =40px,最终宽度80px */
.item3 {
background-color: rgb(216, 210, 249);
flex-shrink: 0;
} /* 不缩小,宽度保持120px */
</style>
展示效果
4. flex-basis
:控制项目的初始尺寸
定义项目在主轴上的 “初始尺寸”,默认值为auto
(即项目自身的尺寸,如width
或height
)。
- 若主轴为水平方向(
row
),flex-basis
优先级高于width
(设置flex-basis
后,width
失效); - 若主轴为垂直方向(
column
),flex-basis
优先级高于height
; - 可设置具体数值(如
200px
、50%
),也可设auto
或0
。
代码示例:
.container { display: flex; }
.item {
flex-basis: 150px; /* 主轴水平,初始宽度150px,width会失效 */
width: 100px; /* 无效,被flex-basis覆盖 */
height: 50px;
}
5. flex
:flex-grow
+ flex-shrink
+ flex-basis
简写
为简化代码,flex
是三者的复合属性,语法:
flex: <flex-grow> <flex-shrink> <flex-basis>;
常用简写场景(必须牢记):
简写形式 | 等价完整写法 | 适用场景 |
---|---|---|
flex: 1 | flex: 1 1 0% | 项目平均分配剩余空间(如等分导航栏) |
flex: auto | flex: 1 1 auto | 项目先按自身尺寸排列,再分配剩余空间 |
flex: none | flex: 0 0 auto | 项目不放大、不缩小,按自身尺寸排列(固定尺寸) |
flex: 0 1 auto | (默认值) | 项目不放大、允许缩小,按自身尺寸排列 |
实战建议:实际开发中几乎不用单独写flex-grow
/flex-shrink
/flex-basis
,而是直接用flex
简写。
6. align-self
:单个项目的交叉轴对齐
控制单个项目在交叉轴上的对齐方式,可覆盖容器的align-items
属性,默认值为auto
(即继承容器的align-items
)。
取值与align-items
完全一致:auto
、stretch
、flex-start
、flex-end
、center
、baseline
。
代码示例(大部分项目垂直居中,单个项目靠下):
<template>
<div class="container">
<div class="item item1"></div>
<div class="item item2"></div>
<div class="item item3"></div>
</div>
</template>
<script setup lang="ts"></script>
<style>
.container {
display: flex;
height: 200px;
align-items: center; /* 容器默认垂直居中 */
border: 1px solid #000;
}
.item {
width: 100px;
height: 50px;
background: #fbbc05;
}
.item2 {
align-self: flex-end;
} /* 单个项目靠下对齐,覆盖容器的align-items */
</style>
展示效果
五、Flex 布局实战案例
掌握属性后,通过实战案例巩固应用,以下是 3 个高频场景。
案例 1:水平垂直居中(最经典)
传统布局实现垂直居中需要复杂的 hack(如position + transform
),Flex 只需 2 行代码:
<template>
<div class="container">
<div class="box">我是水平垂直居中的内容</div>
</div>
</template>
<script setup lang="ts"></script>
<style>
.container {
display: flex;
width: 500px;
height: 300px;
background: #e8eaed;
/* 核心代码 */
justify-content: center; /* 主轴居中(水平) */
align-items: center; /* 交叉轴居中(垂直) */
}
.box {
width: 200px;
height: 100px;
background: #4285f4;
color: white;
text-align: center;
line-height: 100px;
}
</style>
案例 2:自适应导航栏(左 Logo + 右菜单)
需求:Logo 居左,菜单居右,导航栏自适应宽度。
<template>
<nav class="navbar">
<div class="logo">MyLogo</div>
<ul class="menu">
<li>首页</li>
<li>关于</li>
<li>联系</li>
</ul>
</nav>
</template>
<script setup lang="ts"></script>
<style>
.navbar {
display: flex;
justify-content: space-between; /* 主轴两端对齐,Logo左、菜单右 */
align-items: center; /* 垂直居中 */
padding: 0 20px;
height: 60px;
background: #202124;
color: white;
}
.logo {
font-size: 20px;
font-weight: bold;
}
.menu {
display: flex; /* 菜单内部横向排列 */
list-style: none;
gap: 20px; /* 菜单项间距(替代margin) */
}
</style>
案例 3:自适应卡片布局(响应式)
需求:卡片一行最多排 3 个,屏幕变小时自动换行,且卡片间距均匀
<template>
<div class="card-container">
<div class="card">卡片1</div>
<div class="card">卡片2</div>
<div class="card">卡片3</div>
<div class="card">卡片4</div>
<div class="card">卡片5</div>
</div>
</template>
<script setup lang="ts"></script>
<style>
.card-container {
display: flex;
flex-wrap: wrap; /* 溢出换行 */
gap: 20px; /* 卡片间距(行+列) */
padding: 20px;
background: #f5f5f5;
}
.card {
flex: 1 1 calc(33.333% - 20px); /* 核心:1/3宽度,减去gap的影响 */
min-width: 250px; /* 最小宽度,屏幕过小时不再缩小 */
height: 200px;
background: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
display: flex;
justify-content: center;
align-items: center;
font-size: 18px;
}
</style>
calc(33.333% - 20px)
:确保卡片宽度为 1/3 容器宽度,同时减去gap
的间距,避免换行异常;min-width: 250px
:当屏幕宽度过小时(如手机),卡片不再缩小,而是自动换行,实现响应式。
六、常见误区与注意事项
- 容器的
float
/clear
失效:Flex 容器的float
、clear
属性不生效,若需容器水平居中,直接给容器设置margin: 0 auto
即可。 flex-basis
与width
的优先级:主轴为row
时,flex-basis
优先级高于width
;若flex-basis: auto
,则width
生效。align-content
仅作用于多行:若项目未换行(flex-wrap: nowrap
),align-content
无效,需用align-items
。- 项目的
margin: auto
可强制对齐:若给项目设置margin-left: auto
,项目会被推到主轴右侧(类似flex-end
),可用于实现 “左 Logo + 右菜单” 的简化版。
七、总结
Flex 布局是现代前端布局的 “瑞士军刀”,其核心是通过 “容器 - 项目” 和 “主轴 - 交叉轴” 的模型,实现灵活的对齐与空间分配。掌握以下关键点,即可应对 90% 以上的布局需求:
- 容器属性:
flex-direction
(主轴方向)、justify-content
(主轴对齐)、align-items
(单行交叉轴对齐); - 项目属性:
flex
(简写,控制放大缩小)、align-self
(单个项目交叉轴对齐); - 实战技巧:
flex: 1
等分空间、justify-content + align-items
居中、flex-wrap + gap
自适应换行。
通过多练习实际案例(如导航栏、卡片列表、表单布局),即可彻底熟练 Flex 布局,告别传统布局的繁琐与 hack。