2. Flexbox布局:掌握主轴与交叉轴,实现弹性伸缩布局
Flexbox,全称 Flexible Box,说白了就是「弹性盒子」。
我刚开始做前端那会儿,布局全靠 float 和 position。每次做垂直居中,都得写一堆 hack 代码。后来 Flexbox 一出来,我整个人都舒服了。它解决了一个核心问题:让容器内的元素能自动适应空间,不管尺寸是固定的还是动态的。
2.1 核心概念:主轴与交叉轴
Flexbox 有两个轴,这是理解它的关键。
- 主轴(Main Axis):由
flex-direction决定。默认是水平方向(从左到右)。 - 交叉轴(Cross Axis):垂直于主轴。主轴是水平,交叉轴就是垂直。
你想想看,这两个轴就像十字坐标。所有子元素的排列、对齐、换行,都围绕这两个轴展开。
核心公式:主轴控制排列方向,交叉轴控制对齐方式。
2.2 容器属性:掌控全局
先看容器(父元素)上的属性。我习惯把它们分成三组:方向、换行、对齐。
2.2.1 flex-direction:决定主轴方向
.container {
display: flex;
flex-direction: row; /* 默认值,水平从左到右 */
flex-direction: row-reverse; /* 水平从右到左 */
flex-direction: column; /* 垂直从上到下 */
flex-direction: column-reverse; /* 垂直从下到上 */
}
嗯,这里要注意:row-reverse 和 column-reverse 不只是方向变了,起始点和结束点也互换了。我在项目中遇到过一个问题:用 row-reverse 做导航栏的右对齐,结果子元素的顺序全反了。后来我改用 justify-content: flex-end,才搞定。
2.2.2 flex-wrap:控制换行
.container {
flex-wrap: nowrap; /* 默认,不换行,强行压缩 */
flex-wrap: wrap; /* 换行,从上到下 */
flex-wrap: wrap-reverse; /* 换行,从下到上 */
}
默认的 nowrap 会让所有子元素挤在一行。如果内容太多,子元素会被压缩。我曾经踩过一个坑:卡片列表用了 nowrap,结果小屏上卡片被压成了细条,文字都叠在一起了。所以做响应式布局时,flex-wrap: wrap 几乎是标配。
2.2.3 justify-content:主轴对齐
.container {
justify-content: flex-start; /* 默认,起始端对齐 */
justify-content: flex-end; /* 结束端对齐 */
justify-content: center; /* 居中 */
justify-content: space-between; /* 两端对齐,中间等距 */
justify-content: space-around; /* 每个元素两侧间距相等 */
justify-content: space-evenly; /* 所有间距完全相等 */
}
我个人最常用的是 space-between 和 center。比如做导航栏,左边 logo、右边菜单,用 space-between 一行代码搞定。
2.2.4 align-items:交叉轴对齐
.container {
align-items: stretch; /* 默认,拉伸填满 */
align-items: flex-start; /* 起始端对齐 */
align-items: flex-end; /* 结束端对齐 */
align-items: center; /* 居中 */
align-items: baseline; /* 基线对齐 */
}
垂直居中?align-items: center 就完了。以前用 position: absolute 加负 margin 的日子,一去不复返了。
2.2.5 align-content:多行对齐
这个属性只在 flex-wrap: wrap 且有多行时生效。它控制的是整行在交叉轴上的分布。
.container {
align-content: stretch; /* 默认 */
align-content: flex-start;
align-content: flex-end;
align-content: center;
align-content: space-between;
align-content: space-around;
}
小技巧:如果 align-content 没效果,先检查一下 flex-wrap 是不是 wrap,以及容器高度是否大于子元素总高度。
2.3 项目属性:精细控制每个元素
容器属性管全局,项目属性管个体。我一般用这三个:flex、align-self、order。
2.3.1 flex:伸缩因子
flex 是 flex-grow、flex-shrink、flex-basis 的缩写。我建议直接写 flex 简写,别拆开写,容易乱。
.item {
flex: 1; /* 等分剩余空间 */
flex: 0 0 200px; /* 固定宽度 200px,不伸缩 */
flex: 1 1 auto; /* 默认值 */
}
举个例子:三个卡片,想让中间那个占两倍空间,其他各占一倍。
.card { flex: 1; }
.card-center { flex: 2; }
我在项目中遇到过一个问题:用 flex: 1 做等分,结果内容太长的元素把其他元素挤变形了。后来加了 min-width: 0 才解决。嗯,这个坑很多人都会踩。
2.3.2 align-self:单独覆盖对齐
.item {
align-self: auto; /* 继承容器的 align-items */
align-self: flex-start;
align-self: flex-end;
align-self: center;
align-self: stretch;
align-self: baseline;
}
比如一行里大部分元素居中,但某个元素想靠底部。用 align-self: flex-end 就行,不用改容器属性。
2.3.3 order:改变排列顺序
.item {
order: 0; /* 默认值,按源码顺序 */
order: 1; /* 排到后面 */
order: -1; /* 排到前面 */
}
我曾经用 order 做移动端适配:PC 上图片在左边、文字在右边;移动端用 order 把图片调到文字下面。不用改 HTML 结构,爽得很。
注意:order 只改变视觉顺序,不影响键盘导航和屏幕阅读器的顺序。做无障碍时要小心。
2.4 实战:经典布局案例
2.4.1 圣杯布局(三栏自适应)
.container {
display: flex;
min-height: 100vh;
}
.left, .right {
flex: 0 0 200px; /* 固定宽度 */
}
.center {
flex: 1; /* 自适应 */
}
这个布局我用了好几年。左右固定,中间自适应。简单、稳定、不出错。
2.4.2 垂直居中
.container {
display: flex;
justify-content: center;
align-items: center;
}
就两行代码。以前用 table-cell 或者 position 折腾半天,现在一行搞定。
2.4.3 等分布局
.container {
display: flex;
}
.item {
flex: 1;
}
不管几个子元素,自动等分。我做过一个仪表盘,6 个指标卡片,用这个方案,加一个减一个都不用改 CSS。
2.5 避坑指南
我总结几个常见坑,都是我曾经踩过的:
- 子元素被压缩:给子元素加
flex-shrink: 0或者min-width。 - 内容溢出:容器加
overflow: hidden或min-width: 0。 - align-content 不生效:检查
flex-wrap和容器高度。 - order 导致焦点顺序错乱:尽量少用,或者配合
tabindex调整。
核心原则:主轴管排列,交叉轴管对齐。记住这个,Flexbox 就掌握了一半。
2.6 知识体系图
这张图把 Flexbox 的核心脉络理清了。左边是容器属性,右边是项目属性,下面是主轴与交叉轴。你照着这个结构去学,不会乱。
我的建议:别死记硬背属性值。打开浏览器开发者工具,边调边看效果。Flexbox 是「所见即所得」的,调几次就熟了。
好了,Flexbox 的核心内容就这些。主轴与交叉轴、容器与项目属性、常见布局与避坑,你都掌握了。下一节我们聊 Grid 布局,那又是另一个维度了。