05Flex 弹性布局

Flex 是现代 CSS 布局的绝对主力:一行 display: flex, 子元素立刻从「竖着堆」变成「横着排」,对齐、分配、换行全部听指挥。 本章是 CSS 布局的重中之重,请务必边改边看右边的实时预览。

约 30 分钟 14 个动手实验 页面布局绝对主力

一、主轴与交叉轴:先建坐标系

学 Flex 之前必须先立好坐标系,否则后面所有属性都会记混。Flex 容器里有两条轴: 主轴(main axis)是项目排队走的方向, 交叉轴(cross axis)永远垂直于主轴。 默认情况下(flex-direction: row)主轴水平向右、交叉轴垂直向下—— 但只要把方向改成 column,两根轴就会整体互换。

  • justify-content —— 管主轴上的对齐与空间分配;
  • align-items —— 管交叉轴上的对齐。
.rowdisplay: flex 下面补一行 flex-direction: column,两根轴立刻互换、项目改竖着排
记忆口诀:justify 管「排队方向」,align 管「垂直于排队的方向」。 改成 column 之后,justify-content 管的就变成竖直方向、align-items 管水平方向—— 属性没变,轴换了。

二、display: flex:起手式

在父元素上写一行 display: flex,它就变成弹性容器(flex container), 所有直接子元素自动升级为弹性项目(flex item): 块级子元素不再竖着堆,而是沿主轴排成一行;宽度也不再撑满整行,而是收缩为内容宽度。 注意子元素用的还是同一套 HTML,一个字都没改——变的只是父级的一个属性。

同一组子元素:上面竖着堆、下面横着排——把 .flexeddisplay: flex 删掉,下面立刻退回竖排
三个常见误区:① flex 只影响直接子元素,孙元素不管; ② 子元素身上的 float、clear、vertical-align 在 flex 里全部失效,所以「Flex 排版不用清浮动」; ③ 想让弹性容器本身像行内元素一样跟文字并排,用 display: inline-flex

三、flex-direction:主轴朝哪边

flex-direction 决定主轴的方向,也决定了项目「从哪头往哪头排」。四个取值一张表看全:

flex-direction 取值行为分析
取值方向排列起点备注
row水平左 → 右默认值,项目沿 x 轴排
row-reverse水平右 → 左只是换起点,不是镜像镜子
column垂直上 → 下主轴变成 y 轴,两轴互换
column-reverse垂直下 → 上同样只改起点
四种 direction 的排队结果:把 .revflex-direction: row-reverse 换成 row,第二个舞台立刻改成从左排
做「页面主体 + 底部 Tab 栏」这类结构时,外层容器用 flex-direction: column, 主体区写 flex: 1 吃掉剩余高度——这是移动端页面最常用的骨架(本章第九节会实战)。

四、justify-content:主轴上怎么分空间

项目排完队,主轴上剩下的空隙怎么处理?justify-content 说了算。 它是「导航两端对齐」「按钮组居中」「卡片等距分布」背后的功臣,六个取值:

justify-content 取值行为分析(主轴对齐)
取值效果典型场景
flex-start全部挤在主轴起点普通列表(默认)
flex-end全部挤在主轴终点靠右的操作按钮
center整体居中,项目挨在一起居中的标签组
space-between两端贴边,中间间距相等顶栏(logo 左、菜单右)
space-around每个项目两侧间距相等(中间 = 边缘 × 2)均匀分布的图标
space-evenly所有间隔完全相等等距分布
六种分配直观对比:把 .betweenspace-between 改成 space-evenly,两端立刻不再贴边
最常背混的是 around 和 evenly:around 是「每个项目自带一圈」, 所以相邻两个项目的间距会叠成两倍;evenly 干脆所有缝一样宽。 分不清就都试试,眼睛比脑子快。

五、align-items:交叉轴上怎么对齐

主轴排好了,交叉轴方向项目们靠哪边、怎么对齐?align-items 管「一行项目的集体站位」。 注意默认值 stretch 很特殊:项目不写高度时会被拉到和最高的一样高—— 这就是 Flex「天生等高」的秘密。

align-items 取值行为分析(交叉轴对齐)
取值效果备注
stretch拉伸填满交叉轴默认,只项目没写高度时有效
flex-start交叉轴起点对齐row 方向 = 顶对齐
flex-end交叉轴终点对齐row 方向 = 底对齐
center交叉轴居中最常见的垂直居中
baseline按文字基线对齐字号不同时看得最清楚
四行交叉轴对比:把 .midcenter 改成 stretch,中间那个高项目立刻被拉回顶到底填满
为什么 Flex 里的项目「默认等高」?正是 stretch 在起作用:项目没写高度时, 会被拉到整行那么高。所以「多列卡片等高」这个当年的大难题,在 Flex 里是默认行为。

六、换行三件套:flex-wrap / align-content / gap

默认 flex-wrap: nowrap:项目再多也死挤一行, 挤不下就互相压缩(配合后文的 flex-shrink)。改成 wrap 才会换行; 换行之后,行与行在交叉轴上怎么摆,交给 align-content; 而项目之间的间距,现代写法用 gap

换行与多行对齐三件套
属性作用关键点
flex-wrapnowrap 死挤一行 / wrap 自动换行默认 nowrap
align-content行与行之间在交叉轴的分布只在多行(wrap)时生效
gap项目之间的间距row-gap / column-gap 分开设
nowrap 把 5 张卡硬压进一行、wrap 自动换行:把 .wrapflex-wrap: wrap 删掉,第二框立刻挤成一排变瘦
align-content 与 align-items 别混:align-items 管「同一行里」项目怎么对齐; align-content 管「行与行」整体怎么摆——只在换行(多行)时才有效, nowrap 下写了也白写。取值和 justify-content 一模一样(center / space-between / …)。

七、子项三属性:flex-grow / flex-shrink / flex-basis

前面六节都写在容器上,接下来三个属性写在项目上, 合称「flex 三兄弟」,共同决定每个项目占多大地方:

  • flex-basis —— 主轴上的初始尺寸,优先级高于 width(默认 auto:看内容/宽度);
  • flex-grow —— 有剩余空间时,按比例瓜分(默认 0:不瓜分);
  • flex-shrink —— 空间不足时,按比例压缩(默认 1:人人可压)。
flex 简写:flex-grow flex-shrink flex-basis
写法等价展开含义
flex: 1flex: 1 1 0先清零再平分,等分布局首选
flex: 2 1 autogrow=2 shrink=1 basis=auto先保住内容,再按比例伸
flex: 0 0 240pxgrow=0 shrink=0 basis=240px尺寸焊死,不伸不缩(固定侧栏)
flex: autoflex: 1 1 autogrow 为 1,但 basis 取内容宽
侧栏 76px 写死 + flex-shrink: 0,主区 flex-grow: 1 吃掉剩余空间——把侧栏 width 改成 120 试试
grow 按「份数」瓜分空间——1 : 2 : 1:把 .g2 的 grow 改成 3,中间立刻变得更宽
HTML 顺序是 A B C,视觉顺序却是 B C A:把 .o2 的 order 改成 0,B 立刻挪到最前面
flex: 1 为什么能「完美平分」?因为它的 basis 是 0:先把所有项目的初始尺寸当成 0, 剩余空间 = 整个容器,再按 grow 比例分——所以每个项目严格等宽。而 flex: auto(basis 取内容宽) 是「先保住内容,再分剩下的」,两者结果常常不同。

八、align-self:给单个项目「开小灶」

容器上的 align-items 是集体口令,项目上的 align-self 是个人请假条: 取值完全相同(stretch / flex-start / flex-end / center / baseline), 但只对自己生效,会覆盖容器设置。聊天界面「自己的消息靠上、别人的靠下」就靠它。

其余项目默认顶对齐,2 号居中、4 号贴底——给第一个项目也加一句 align-self: flex-end 试试
同理还有 order(上一节)也是「项目级」属性。项目能覆盖容器的口令, 项目级能覆盖的只有:align-self、order、flex 三兄弟——其余都得听容器的。

九、经典实战四连

学完属性,来四个真实到可以直接抄走的配方:等宽导航、完美居中、圣杯布局、底部固定页脚。 每个都是面试与日常的高频题。

五个导航项自动等宽:删掉一个 .it、或把「首页」的 class 去掉 on 试试,宽度都自动重排
一行内容、一张卡片,都能两行 CSS 居中——把 .fx-centeralign-itemsflex-start,卡片立刻顶上
左右 86px 固定,中间 flex: 1 自适应——把左栏 width 改成 140,主区自动变窄
内容很少时页脚也贴底:把 .contentflex: 1 删掉,footer 立刻被拽到中间

十、Flex 属性速查表

把整章属性的取值归拢到两张表,背下来即可覆盖 90% 的实战。

容器六属性速查
属性取值作用
flex-directionrow / row-reverse / column / column-reverse决定主轴方向
flex-wrapnowrap / wrap是否换行
flex-flow上面两者简写flex-flow: row wrap
justify-contentflex-start / flex-end / center / space-between / space-around / space-evenly主轴空间分配
align-itemsstretch / flex-start / flex-end / center / baseline交叉轴单行对齐
align-content同 justify-content + stretch交叉轴多行分布(需 wrap)
gap长度值项目间距(含换行后的行距)
项目四属性 + align-self 速查
属性取值作用
flex-grow数字(默认 0)剩余空间按份数伸展
flex-shrink数字(默认 1)空间不足时按份数收缩
flex-basis尺寸 / auto(默认 auto)主轴初始尺寸,优先于 width
flex1 / 0 0 auto 等简写三兄弟一次写完
order数字(默认 0)改变视觉顺序
align-self同 align-items覆盖容器的交叉轴对齐

十一、本章小结

  • 两根轴定乾坤:justify-content主轴align-items交叉轴;direction 一换,两轴跟着换。
  • 容器六件套:flex-directionjustify-contentalign-itemsflex-wrapalign-content(多行才生效)、gap
  • 项目四件套:flex-grow(分剩余)、flex-shrink(压不足)、flex-basis(初始尺寸)、order(视觉排序),外加 align-self(个人对齐)。
  • flex: 1 = 1 1 0:先清零再平分,等分布局首选。
  • 四大配方直接背:等宽导航 flex: 1;完美居中 justify-content + align-items;圣杯 固定宽 + flex: 1;沉底页脚 column + flex: 1 + min-height
  • Flex 是一维布局;行 列要同时排,交给下一课的 Grid。
动手练习:做一个「个人主页卡片」:顶部头像 + 昵称用 flex 排(头像固定 64px,昵称区 flex: 1); 中间一行三个数据(作品 / 粉丝 / 关注)等宽分布; 底部两个按钮一个靠左一个靠右(想想用 space-between 还是 margin-left: auto); 整个卡片外层再用 column + flex: 1 让「关注」按钮沉底。