先记住这个答案
主轴由 flex-direction 决定:row 或 row-reverse 沿行内方向排列,column 或 column-reverse 沿块方向排列;交叉轴总是垂直于主轴。关键点是 flex 使用的是逻辑方向而非左右上下:在英文横向书写下 row 的主轴从左向右,在阿拉伯语 RTL 下变为从右向左,在 vertical-rl 竖排下主轴则从上向下。因此判断 justify-content 和 align-items 的作用方向时,必须先确认 flex-direction 与书写模式的组合。
- 主轴由 flex-direction 决定,交叉轴恒垂直于它
- flex 用逻辑方向,物理指向随书写模式变化
- direction 只翻转行内轴,竖排会同时旋转两轴
两轴如何由 flex-direction 与书写模式共同确定
Flex 规范把方向定义为逻辑概念:main-start、main-end、cross-start、cross-end,而不是 left、right、top、bottom。flex-direction 的四个值决定主轴落在哪条逻辑轴上:row 系列沿行内轴,column 系列沿块轴;reverse 只交换起点和终点,不改变轴本身。交叉轴则被定义为与主轴垂直的另一条逻辑轴,没有独立属性控制它。
书写模式决定逻辑轴与物理方向的映射。horizontal-tb 加 LTR 时,行内轴从左向右、块轴从上向下;direction: rtl 会把行内轴翻转为从右向左,row 的主轴随之反向,但块轴不变。writing-mode: vertical-rl 时行内轴变为从上向下、块轴从右向左,于是 row 的主轴变成纵向,column 的主轴变成横向,两轴整体旋转了九十度。
竖排中文工具栏的对齐方向推导
需求是做一个古籍阅读页的竖排控制条:容器设 writing-mode: vertical-rl,三个按钮要沿竖直方向依次排开并水平居中。判断过程:竖排下行内轴是从上向下,所以 flex-direction: row 的主轴就是竖直方向,按钮天然纵向排列;justify-content: center 控制竖直分布,align-items: center 控制的是交叉轴,即水平的左右方向。最终用 align-items: center 实现水平居中。
这样处理的原因是所有 flex 对齐属性都绑定在逻辑轴上而非物理轴上。如果凭直觉认为 row 一定水平、align-items 一定管竖直,在竖排下会写反两个属性。推导顺序固定为:先由 writing-mode 和 direction 确定行内轴与块轴的物理指向,再由 flex-direction 把主轴映射上去,最后交叉轴取垂直方向,每一步都不依赖记忆而可重现。
.toolbar {
display: flex;
flex-direction: row; /* 竖排下主轴为竖直方向 */
writing-mode: vertical-rl; /* 行内轴:上 → 下 */
justify-content: center; /* 沿主轴:竖直居中 */
align-items: center; /* 沿交叉轴:水平居中 */
height: 100vh;
}适用于支持 writing-mode 的现代浏览器。要点是 row 的物理方向由书写模式决定,而非固定水平。
两轴推导容易失效的条件
最常见的失效是把物理方向当成恒定:在 RTL 页面复用为 LTR 写的 flex 布局时,justify-content: flex-start 会贴到右侧而不是左侧;row-reverse、column-reverse 也会交换起止边,使 flex-start 出现在视觉上的末端。另一个坑是 writing-mode 只写在祖先元素上,子级 flex 容器继承了竖排模式,导致看起来 row 莫名其妙变成了竖排。
对应处理是统一用逻辑思维审查代码:调试时先读容器的 computed style 确认 flex-direction、direction、writing-mode 三个值,再推导两轴。代价是团队需要放弃左右的表述习惯;如果某组件确实需要固定物理方向,应显式在组件根上设置 direction: ltr 或 writing-mode: horizontal-tb 锁定环境,避免被外部书写模式污染。
容易答错的地方
- 认为 row 永远水平、column 永远垂直
- row 沿行内轴、column 沿块轴,物理方向由书写模式决定。vertical-rl 下 row 的主轴是竖直的,column 反而是横向的,固定记忆会在竖排布局中全面失效。
- 以为 direction: rtl 会同时翻转两条轴
- direction 只翻转行内轴:当主轴为 row 系列时,它交换主轴起止;当主轴为 column 系列时,它交换交叉轴起止。块轴方向由 writing-mode 决定,flex-wrap 的 reverse 形态会单独交换交叉轴起止,但不改变轴的方向。
面试官还会怎么问?
main-start 和 main-end 具体指什么?
它们是主轴起点与终点的逻辑边。row 加 LTR 时 main-start 在左;RTL 时在右;row-reverse 与书写模式的效果叠加。justify-content 的 flex-start 与 flex-end 就是以这两条逻辑边为参照的。
交叉轴的起点和终点由什么决定?
cross-start 与 cross-end 由交叉轴所对应的逻辑轴决定:若主轴为 row,交叉轴沿块轴,由 writing-mode 决定;若主轴为 column,交叉轴沿行内轴,由 direction 决定。flex-wrap: wrap-reverse 会交换二者,使换行向交叉轴起点方向堆叠,但它不改变主轴方向。
如何快速判断 justify-content 作用的物理方向?
按三步:查容器 computed style 的 writing-mode 与 direction 确定行内轴指向,再看 flex-direction 是 row 还是 column 把主轴映射到物理方向,最后确认是否带 reverse。justify-content 永远沿这条主轴作用。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。