CSS Flexbox:弹性布局入门 · Lesson 3 of 5

第 3 课:flex-direction 与主轴的转向

本课目标:

  • 说出 flex-direction 做什么,并列出它的四个值。
  • 解释为什么 justify-content 不是“水平属性”。
  • 预测主轴变成竖列后,哪个属性负责上下移动 item。

先修条件:第 2 课(justify-content = 主轴,align-items = 交叉轴) | 上一篇 << 02 | 下一篇 04 >>

“justify-content = 水平方向”失灵的那一刻

第 2 课里你学到 justify-content 左右移动 item。这没错,直到它出错。你把 item 竖着排成一列的那一瞬间,justify-content 开始上下移动它们;如果你把它背成了“管水平的那个”,你现在就在和自己的布局较劲。始终学不顺 Flexbox 的人,多半是按属性的默认方向去记它们,而不是按轴去记。这一课把“水平”换成那个真正成立、而且永远不变的说法。

讲解

flex-direction 设定 flex item 在容器里的摆放方式,它定义主轴以及 item 流动的方向1。它有四个值,默认是 row1

  • row(默认):主轴沿行的方向,从左到右,就是你已经熟悉的水平方向。
  • row-reverse:同一条轴,但 item 从右边开始排。
  • column:主轴改为从上到下,沿块的方向2
  • column-reverse:同一条垂直轴,item 从底部开始排。

不变的规则在这里:justify-content 永远跟着主轴,align-items 永远跟着交叉轴flex-direction 决定主轴指向哪里,也就决定了这两个属性各自实际做什么。属性本身没有任何变化,只是它们钉在的那条轴转了方向。

从上往下读这张图:flex-direction 是开关。选 row,主轴水平,于是 justify-content 管水平。选 column,主轴垂直,于是同一个 justify-content 变成管垂直。属性没变,只是它骑着的那条轴转了九十度。

这也是为什么竖直菜单和侧边栏在 Flexbox 里非常自然:设 flex-direction: column,item 就竖着排,然后 justify-content 在垂直方向拉开间距,align-items 负责它们的左右对齐。还是那两个属性,只是轴转了。

是起点和终点,不是左和右

这就是为什么整门课一直说“主轴起点”而不说“左边”。Flexbox 对文档的书写模式不作任何假设2。在英文环境下写 flex-direction: row,主轴的起始边在左、结束边在右;但换成从右往左书写的阿拉伯语,主轴的起始边就在右边、结束边在左边2。CSS 一个字都没改,是这条轴的起点挪了位置。

这才是 flex-startflex-end 真正命名的东西:一条轴的起始线和结束线,按文档的书写方向去解析2。在上面英文和阿拉伯语这两种情况里,交叉轴都仍然从顶部开始、到底部结束,因为两者都是横向书写模式2。裸的 startend 这两个值同样是书写模式感知的3

实践上:如果你写了 justify-content: flex-end,item 却落在了你没想到的那一侧,先查书写方向,再怀疑属性。rowrow-reverse 这两个值会受 flex 容器方向性的影响——在从右往左的方向下,row 是从右往左走,row-reverse 反而从左往右走1

-reverse 到底反转了什么

row-reversecolumn-reverse 并不动轴的方向,它们交换的是哪一端算主轴起点1。于是 item 从相反的那一端开始排,视觉顺序也整体反过来。这确实有用——但它有一个代价,值得在你伸手去用之前就知道。

row-reversecolumn-reverse 会让屏幕上的视觉顺序和标记里的 DOM 顺序脱节。屏幕阅读器用户跟的是 DOM 顺序,所以他们接收到的内容次序和视力正常的用户看到的不一样,这会实实在在损害依赖辅助技术导航的人的体验1。如果这个视觉顺序是承载含义的,就去改 HTML 的顺序,而不要用 CSS 反转。

读别人代码时还有一个简写值得认得:flex-flowflex-directionflex-wrap 合成一条声明,所以 flex-flow: row wrap 一次设定两者2。换行那一半由第 5 课负责。

完整示例(跟着做)

一个竖直侧边导航,上下均匀分布,每个链接左右居中:

用规则走一遍。flex-direction: column 让主轴变垂直。justify-content: space-between 作用在主轴上,所以它把链接沿垂直方向拉开:第一个在顶部,最后一个在底部,间距均匀。align-items: center 作用在交叉轴上,交叉轴现在是水平的,所以每个链接左右居中。如果你原本指望 justify-content 水平分布它们,column 这一翻转正是会让你意外的地方。

你来试试(填空示例)

你想让三个按钮竖着堆叠,并钉在一个高容器的底部。填上两行:

答案:flex-direction: column(主轴变垂直)和 justify-content: flex-end(主轴终点现在是底部)。因为主轴指向下方,flex-end 就是底部,而沿这条轴移动的属性正是 justify-content。把它读成“哪条轴、哪一端”,column 翻转就不再是陷阱。

小结 + 下节课预告

flex-direction 决定主轴指向哪里;justify-content 跟着主轴,align-items 跟着交叉轴,无论它们指向何方。用“主轴/交叉轴”换掉“水平/垂直”,column 翻转就不再让你吃惊。到目前为止,每个 item 都按自己的自然尺寸占位。下一课我们让 item 分享剩余空间,flex-growflex-shrinkflex-basis 就在那里登场,而所有误解里最大的那一个也在那里:flex: 1 到底在分什么。

Footnotes

  1. MDN: flex-direction — https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/flex-direction 2 3 4 5

  2. MDN: Basic concepts of flexbox — https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Flexible_box_layout/Basic_concepts 2 3 4 5 6

  3. MDN: Aligning items in a flex container — https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Flexible_box_layout/Aligning_items

Exercises

01

在你自己的文件里,搭一个 display: flex 的容器,三个子元素,固定高度。加上 justify-content: center,观察它水平居中。现在加上 flex-direction: column 并刷新。记下 item 和居中方向各自怎么变了。

第 1 级(热身)
Done criteria · checked locally
02

在刷新之前,先预测 align-items: flex-end 在 flex-direction: column 的容器里会做什么。然后验证。

第 2 级(进阶)
Done criteria · checked locally

My note

Jot down thoughts, sticking points, things you didn't get. Written to this course's appendix only — the lesson file is never touched.