今天系统复习了 Flexbox 的核心属性,包括主轴与交叉轴、对齐方式、弹性伸缩计算、三栏布局实战、换行与多行对齐、以及 align-self 和 order 的进阶用法。以下是当天的问答整理与知识总结。
一、Flexbox 基础:主轴与交叉轴
1. 主轴方向 与 flex-direction
| 属性值 | 主轴方向 | 交叉轴方向 |
| row | 水平从左到右 | 垂直从上到下 |
| row-reverse | 水平从右到左 | 垂直从上到下 |
| column | 垂直从上到下 | 水平从左到右 |
| column-reverse | 垂直从下到上 | 水平从左到右 |
|---|
注意: justify-content 控制主轴 对齐,align-items 控制交叉轴对齐。当 flex-direction 改变时,主/交叉轴的方向随之改变。
2. 主轴对齐:justify-content
- flex-start:起始位置对齐
- flex-end:结束位置对齐
- center:居中对齐
- space-between:两端对齐,中间间距相等
- space-around:每个子项左右边距相等,相邻子项间距是子项到父容器边距的两倍
- space-evenly:所有间距(包括两端)完全相等
3. 交叉轴对齐:align-items
- stretch(默认):子项在交叉轴方向拉伸填满容器(前提:子项未设置交叉轴方向的尺寸
- flex-start / flex-end / center:与主轴类似,但方向为交叉轴
- baseline:根据子项的文字基线对齐
stretch 的细节:
在 flex-direction: row 下,交叉轴是垂直方向,stretch 会让子项高度填满父容器;在 column 下,交叉轴是水平方向,stretch 会让子项宽度填满父容器。若子项已设置具体高度/宽度,则 stretch 失效。
二、弹性伸缩计算:flex-grow 与 flex-shrink
1. flex-grow:分配剩余空间
公式:
子项最终宽度 = 子项基础宽度 + (子项 grow / 所有子项 grow 之和) × 剩余空间
示例: 三个子项基础宽度均为 100px,父容器宽 600px,剩余空间 300px。若 flex-grow 分别为 1、2、3,则:
- 总 grow = 6
- 子项1 增加:300 × (1/6) = 50px → 最终 150px
- 子项2 增加:300 × (2/6) = 100px → 最终 200px
- 子项3 增加:300 × (3/6) = 150px → 最终 250px
2. flex-shrink:处理溢出空间
当子项总宽度超过父容器时,按比例缩小。
公式:
每个子项的权重 = 自身宽度 × 自身 shrink
总权重 = 所有子项权重之和
子项缩小宽度 = 溢出宽度 × (子项权重 / 总权重)
示例: 三个子项基础宽度分别为 100px 200px 300px,父容器宽 500px,溢出 100px。
若 flex-shrink 分别为 1、2、3,则:
- 总权重:100 * 1 + 200 * 2 + 300 * 3 = 1400
- 子项1 缩小:100 × (100 * 1 / 1400) ≈ 7.14px
- 子项2 缩小:100 × (200 * 2 / 1400) ≈ 28.57px
- 子项3 缩小:100 × (300 * 3 / 1400) ≈ 64.29px
注意:
- flex-shrink: 0 表示该子项不允许收缩。
- min-width / max-width 优先级高于 flex 伸缩计算,会限制最终尺寸。
3. flex 简写
- flex: 1 → flex-grow: 1; flex-shrink: 1; flex-basis: 0%
- flex: auto → flex-grow: 1; flex-shrink: 1; flex-basis: auto
- flex: none → flex-grow: 0; flex-shrink: 0; flex-basis: auto
对比举例:
**a. 统一条件:**父容器宽度:600px;子 1:width: 100px;子 2:width: 200px
b. flex: 1
- 基础尺寸 0,完全按比例分父容器
- 两个都 flex:1 → 直接平分 600px
- **结果:**子 1:300px;子 2:300px
c. flex: auto
- 基础尺寸 = 自己的 width:100、200
- 剩余空间:600 - 300 = 300px
- 两人平分剩余,各 +150
- 子 1:100 + 150 = 250px;子 2:200 + 150 = 350px
d. flex: none
- 不长大(grow:0)
- 不缩小(shrink:0)
- 尺寸就用自己 width:100、200
三、实战:三栏布局
经典圣杯/双飞翼布局(Flex 版)
css
.container {
display: flex;
}
.left, .right {
width: 200px;
flex-shrink: 0; /* 防止压缩 */
}
.center {
flex: 1; /* 占据剩余空间 */
min-width: 150px; /* 最小宽度限制 */
max-width: 300px; /* 最大宽度限制 */
}
说明:
- 左右固定宽,中间自适应
- flex-shrink: 0 保证左右在容器缩小时不会变形(默认为1,所以需要手动限制)
- min-width 限制中间区域的最小宽度,防止被过度压缩。
- max-width 限制中间区域的最大宽度,防止过大。
补充:
-
min-width: 0 是一个专门解除 flex 子项默认限制的 CSS 属性。(flex 默认 min-width: auto;)
-
解除内容对宽度的 "下限锁定",让 flex-shrink 规则真正生效
-
只有设置了 min-width: 0,text-overflow: ellipsis 才能在 flex:1 的元素上正常工作
-
防止布局溢出: 确保子项宽度始终被限制在父容器内部
css/* 父容器 */ .flex-container { display: flex; width: 200px; /* 父容器很窄 */ } /* 子项 */ .flex-item { flex: 1; /* 想要自适应 */ min-width: 0; /* 关键!不加则会被内容撑宽 */ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; /* 才能生效 */ }
四、换行与多行对齐
1. flex-wrap: wrap 的作用
当子项总宽度超过容器时,允许换行。换行后,容器变为多行结构。
2. align-content vs align-items
| 属性 | 作用范围 | 生效条件 |
| align-items | 单行内的每个子项 | 永远生效 |
| align-content | 多行之间的整体对齐 | 必须有多行(flex-wrap: wrap 且实际换行),且交叉轴方向有剩余空间 |
|---|
**取值:**flex-start、flex-end、center、space-between、space-around、stretch(默认)。
3. justify-content 在多行中的行为
即使换行,justify-content 仍然作用于每一行内部,而不是整个多行容器。
五、子项个性:align-self 与 order
1. align-self
覆盖父级 align-items 的设置,允许单个子项在交叉轴上有不同的对齐方式。
**应用场景:**例如导航栏中,大部分子项垂直居中,但 logo 需要顶部对齐,可对 logo 设置 align-self: flex-start。
2. order
定义子项的排列顺序,数值越小越靠前。默认值为 0,可负值。
- 相同 order 值时,按 DOM 顺序排列。
- 仅改变视觉顺序,不影响 DOM 结构,对无障碍和键盘导航可能有影响。
六、常见追问
1. 如果 flex-direction: column-reverse,justify-content: flex-start 会让子项从哪里开始排列?
答:主轴垂直从下到上,flex-start 会在容器底部开始排列。
2. align-items: stretch 什么时候会失效?
答:当子项在交叉轴方向设置了具体尺寸(如 height 或 width)时。
3. flex: 1 和 flex: auto 有什么区别?
答:flex: 1 的 flex-basis: 0%,表示子项从 0 开始分配剩余空间;flex: auto 的 flex-basis: auto,表示子项先以其内容或宽度为基础,再分配剩余空间。
4. 如果一个子项设置了 flex: 1 和 max-width: 300px,父容器宽度 1000px,其他子项固定宽 100px,那么这个子项最终宽度是多少?
答:首先计算剩余空间:1000 - 200 = 800px。该子项 grow 为 1,其他固定宽子项 grow 为 0,所以它独占剩余空间,理论宽度为 0 + 800 = 800px,但受 max-width: 300px 限制,最终宽度为 300px。(右片区域一大片空白)