跳转至

Flexbox — 一维布局的完整工具箱

这一章讲现代 CSS 用得最多的布局系统。 它解决一类特定问题: 一行(或一列)里挤着好几个盒子,怎么对齐、怎么均分空间、怎么让某一个盒子把剩余空间吃掉。 「垂直居中」这个困扰了 CSS 十五年的老问题,Flexbox 用三行代码解决了1。

1. 这一章在全书链条里的位置

display(第 05 章)给了「站队」的基本姿势;Flexbox 和 Grid 是 display 的两个高级值 (display: flex / display: grid),站队规则全部升级。两章的分工原则书里写得很直白: Flexbox 管一维(行或列),Grid 管二维(行和列同时)2—— 发现自己在拿 Flex 硬凑网格(一层套一层),就是该换 Grid 的信号3。

2. 顶层全景:父管排法,子管身材

.display: flex 的父容器(Flex Container,伸缩容器)
 ┌─────────────────────────────────────────────┐
 │  [item] [item]   [item]          ← 子项(Flex Items) │
 └─────────────────────────────────────────────┘
   │           │            │
   ├─ 主轴方向:由 flex-direction 定,默认水平 →   ← justify-content 管这轴
   └─ 交叉轴:与主轴垂直,默认垂直 ↑             ← align-items 管这轴

图说:两个轴是 Flexbox 的全部世界观。对齐属性挂错轴,是本章第一大错。

三个名词:伸缩容器是声明了 display: flex 的父元素;伸缩项是它的直接孩子; 主轴是子项排列的方向(默认水平),交叉轴是与它垂直的方向4。 注意「直接孩子」——孙辈不参与分配,这点和 Grid 一样。

3. 核心原理:容器侧的四个旋钮

方向与换行

flex-direction: row(默认)/ row-reverse / column / column-reverse——主轴朝哪5。 flex-wrap: nowrap(默认,挤着也不换行)/ wrap / wrap-reverse——装不下时换不换行6。

对齐:justify 与 align 的分工

justify-content 管主轴(默认即水平):子项在行的哪头、间隔怎么分7:

值 效果
flex-start(默认) 挤向起点
flex-end 挤向终点
center 居中
space-between 两头贴边,中间均分
space-around 每个子项两侧等宽空隙
space-evenly 所有空隙等宽

align-items 管交叉轴(默认即垂直),常用 stretch(默认,拉高到行高)、 center(垂直居中)、flex-start/flex-end8。

记法:justify 是「主轴」,align 是「交叉轴」;一旦 flex-direction: column, 主轴变竖,两个属性管的方向就跟着互换——书里把「justify 与 align 搞混」列为本章头号错误9。

gap 管间距:gap: 20px 让相邻子项之间恰有 20px,比给每个子项配 margin 干净—— margin 会在首尾多出来一块,gap 不会。书里补了一句兼容性注记: 2020 年前的浏览器不支持 Flex 里的 gap,如今已全面可用10。

主轴例子(承上):一行三个盒子,均分间隔

.container {
  display: flex;
  justify-content: space-between;
  gap: 20px;
}

子项从起点排到终点,首尾贴边,中间的空隙均分;任何一对相邻子项之间又保底 20px—— 两个属性各管一段,互不打架。

4. 核心原理:子项侧的分配机制

容器管「排法」,子项管「身材」。三个属性合作:

  • flex-basis:分配前的基础尺寸,auto 表示按内容。
  • flex-grow:有剩余空间时,按份数长大。默认 0——不长。
  • flex-shrink:空间不够时,按份数缩小。默认 1——一起缩。

主线例子:侧栏 + 主区,剩余空间全给主区

输入:500px 宽的容器,里面两个子项,要求「侧栏恒定 200px,主区吃掉剩下的」。

.sidebar { flex: 0 0 200px; }  /* 不长、不缩、基础 200px */
.content { flex: 1; }          /* 份数 1 → 吃掉全部剩余 */

走一遍分配:容器 500px。侧栏基础 200px,声明不长不缩,钉死 200px。 剩余 300px。.content 的 flex-grow 是 1,全拿走——主区最终 300px11。 容器缩到 400px 呢?侧栏仍 200(不缩),主区缩到 200(grow 为 0 时的 basis auto 按内容算,收缩按默认 shrink 1 走)——无论容器怎么变,侧栏恒定。 这正是「圣杯布局」里侧栏的写法,后面 Grid 一章会用另一种方式重做它。

三个数字按 grow、shrink、basis 顺序简写成一行 flex: 0 0 200px。 书里建议永远用简写,拆开写又长又容易漏12;最常用两个模板:

flex: 1;         /* = 1 1 0%:可长可缩,基础为零,均分剩余 */
flex: 0 0 200px; /* = 钉死 200px */

单个子项的特权

align-self 让某一个子项不服从容器的 align-items,单独对齐13; margin: auto 有个妙用:margin-left: auto 会把这一个子项推到行的尽头—— 「导航条最右边放一个退出按钮」的标准做法14。

5. 常见模式速览

书里三个模式,都是上面零件的直接组装:

模式 关键代码 干什么
完美居中 justify-content: center; align-items: center; 水平垂直双居中1
分裂导航 .logout { margin-left: auto; } 把一项推到行尾14
卡片组 flex-wrap: wrap; gap: 1rem; + 卡片 flex: 1 1 300px 卡片行自动换行、拉伸、保底 300px15

6. 作者的判断与证据

  • 「Flexbox 不需要 float 或复杂定位」——定位句,把它定义为现代默认16。
  • 「justify 管主轴、align 管交叉轴」的记忆法——教学判断,全书反复用。
  • 「用简写 flex 而不是拆开三个属性」——工程断言,理由(更干净可靠)成立12。
  • 「老浏览器 gap 不支持」——兼容性事实,带年份(2020 年前)10。
  • 证据类型:断言 + 最小例子,无性能或兼容性数据表。

7. 边界与局限

  • 没讲 order(子项排序)与 flex-flow 简写——都是不常用件。
  • 没讲 Flex 的二维能力(align-content 多行对齐)——多行场景本书留给 Grid。
  • 没讲「Flex 子项的 min-width 默认是 auto,内容太大会撑破容器」这个高频坑 (解法 min-width: 0)——本书未收。

判断(我们的,不是书里的): 本章把「主轴/交叉轴」放在最前面讲是正确顺序—— 这个坐标系一旦建立,后面所有属性都有了挂放的位置;反过来先背属性名的教法, 读者永远要在脑子里翻「justify 是横还是竖」。 如果错,会错在: 对完全没有坐标系概念的读者,「主轴随 flex-direction 变」本身 就需要一个动画才能真懂——静态文字讲到这里是合理终点,再往下必须亲手试。

8. 可带走的

  1. display: flex 开世界;主轴 justify、交叉轴 align,换 column 角色互换9。
  2. 子项身材三件套:basis(基础)、grow(长大份数)、shrink(缩小份数),永远用简写12。
  3. flex: 1 均分剩余;flex: 0 0 200px 钉死尺寸——两个模板覆盖八成场景11。
  4. 间距用 gap,不用 margin——首尾不脏10。
  5. 单个元素推到行尾:margin-left: auto(或右推 margin-right: auto)14。
  6. 垂直居中三行:display flex + justify center + align center1。
  7. 拿 Flex 套娃搭网格时停手——那是 Grid 的活(下一章)3。

9. 原文地图

主题 原书章 原文位置
一维布局定位 Chapter 7: Flexbox Reference text/08-ch01-1-chapter-overview.txt:7(搜「one-dimensional」)
容器/子项/两轴 同上 text/08-ch01-1-chapter-overview.txt:21(搜「Flex Container」)
flex-direction 四值 同上 text/08-ch01-1-chapter-overview.txt:45(搜「row-reverse」)
justify-content 六值 同上 text/08-ch01-1-chapter-overview.txt:52(搜「justify-content」)
align-items 五值 同上 text/08-ch01-1-chapter-overview.txt:57(搜「align-items」)
gap 与居中示例 同上 text/08-ch01-1-chapter-overview.txt:62(搜「gap」)
flex-grow/shrink/basis 同上 text/08-ch01-1-chapter-overview.txt:80(搜「ability for a flex item to grow」)
侧栏钉死 + 主区吃掉剩余 同上 text/08-ch01-1-chapter-overview.txt:103(搜「flex: 0 0 200px」)
justify/align 搞混是头号错 同上 text/08-ch01-1-chapter-overview.txt:147(搜「Confusing justify and align」)
gap 的兼容性注记 同上 text/08-ch01-1-chapter-overview.txt:151(搜「pre-2020」)
完美居中 同上 text/08-ch01-1-chapter-overview.txt:113(搜「Perfect Center」)
分裂导航 同上 text/08-ch01-1-chapter-overview.txt:123(搜「Split Navigation」)
卡片组 同上 text/08-ch01-1-chapter-overview.txt:133(搜「Card Group」)
拿 Flex 硬凑网格的警告 同上 text/08-ch01-1-chapter-overview.txt:153(搜「nested flex」)

  1. 出处:「Chapter 7: Flexbox Reference」(text/08-ch01-1-chapter-overview.txt:113,搜「Perfect Center」)。原文:「Centering an element both horizontally and vertically.」示例为 display: flex; justify-content: center; align-items: center; height: 100vh;。 ↩↩↩

  2. 出处:「Chapter 7: Flexbox Reference」(text/08-ch01-1-chapter-overview.txt:7,搜「single axis」)。原文:「a one-dimensional layout model designed for distributing space along a single axis (either a row or a column)」。 ↩

  3. 出处:「Chapter 7: Flexbox Reference」(text/08-ch01-1-chapter-overview.txt:153,搜「nested flex」)。原文:「If you find yourself using many nested flex containers to create a grid, consider using CSS Grid (Chapter 8) instead.」 ↩↩

  4. 出处:「Chapter 7: Flexbox Reference」(text/08-ch01-1-chapter-overview.txt:21,搜「Flex Container」;:25 搜「Main Axis」)。原文:Flex Container 是应用 display: flex 的父元素;Main Axis 默认水平,Cross Axis 垂直。 ↩

  5. 出处:「Chapter 7: Flexbox Reference」(text/08-ch01-1-chapter-overview.txt:45,搜「row-reverse」)。原文:「Values: row (default), row-reverse, column, column-reverse.」 ↩

  6. 出处:「Chapter 7: Flexbox Reference」(text/08-ch01-1-chapter-overview.txt:47,搜「flex-wrap」)。原文:「Controls whether items should wrap to multiple lines.」 ↩

  7. 出处:「Chapter 7: Flexbox Reference」(text/08-ch01-1-chapter-overview.txt:52,搜「justify-content」)。原文:「Aligns items along the Main Axis.」值为 flex-start (default), flex-end, center, space-between, space-around, space-evenly。 ↩

  8. 出处:「Chapter 7: Flexbox Reference」(text/08-ch01-1-chapter-overview.txt:57,搜「align-items」)。原文:「Aligns items along the Cross Axis.」默认值 stretch。 ↩

  9. 出处:「Chapter 7: Flexbox Reference」(text/08-ch01-1-chapter-overview.txt:147,搜「Confusing justify and align」)。原文:「Remember: Justify is for the Main Axis (usually horizontal), Align is for the Cross Axis (usually vertical). If you change flex-direction to column, their roles effectively swap.」 ↩↩

  10. 出处:「Chapter 7: Flexbox Reference」(text/08-ch01-1-chapter-overview.txt:151,搜「pre-2020」)。原文:「In older browsers (pre-2020), gap didn't work in Flexbox. Today it is widely supported and much better than using margins.」 ↩↩↩

  11. 出处:「Chapter 7: Flexbox Reference」(text/08-ch01-1-chapter-overview.txt:103,搜「flex: 0 0 200px」)。原文:「.sidebar { flex: 0 0 200px; } /* Won't grow, won't shrink, stays 200px / .content { flex: 1; } / Grows to fill all remaining space */」。剩余空间的计算(500px 容器 → 主区 300px)是按这个分配规则走的演示,容器宽度 500px 是为演示设的数。 ↩↩

  12. 出处:「Chapter 7: Flexbox Reference」(text/08-ch01-1-chapter-overview.txt:149,搜「shorthand」)。原文:「Writing flex: 1 is cleaner and more reliable than setting flex-grow, flex-shrink, and flex-basis separately.」 ↩↩↩

  13. 出处:「Chapter 7: Flexbox Reference」(text/08-ch01-1-chapter-overview.txt:106,搜「align-self」)。原文:「Allows the default alignment (from align-items) to be overridden for a single item.」 ↩

  14. 出处:「Chapter 7: Flexbox Reference」(text/08-ch01-1-chapter-overview.txt:123,搜「Split Navigation」)。原文:「Pushing a specific item (like a "Logout" button) to the far right.」,.logout { margin-left: auto; }。 ↩↩↩

  15. 出处:「Chapter 7: Flexbox Reference」(text/08-ch01-1-chapter-overview.txt:133,搜「Card Group」)。原文:「Creating a row of cards that wrap and fill the space equally.」,卡片写 flex: 1 1 300px。 ↩

  16. 出处:「Chapter 7: Flexbox Reference」(text/08-ch01-1-chapter-overview.txt:7,搜「modern standard」)。原文:「It is the modern standard for aligning elements, handling responsive resizing, and distributing space between items without needing floats or complex positioning.」 ↩