第 2 课:两条轴,两个属性
本课目标:
- 说出 flex 容器的主轴和交叉轴。
- 把
justify-content对应到主轴,把align-items对应到交叉轴。- 有意识地把一个元素水平加垂直居中,而不是碰运气。
先修条件:第 1 课(
display: flex把 item 摆上主轴) | 上一篇 << 01 | 下一篇 03 >>
你想用 justify-content 把它往下移,它却横着走了
这是 Flexbox 最常见的一种挫败:你想把一个元素往下挪一点,伸手去写 justify-content,元素却横着滑走了。或者你设了 align-items 指望水平居中,结果什么也没发生。这两个属性都没坏。它们各自作用在不同的轴上,而在你能看见这两条轴之前,在它们之间做选择就是抛硬币。这一课先让两条轴现形,再把两个属性各挂到一条轴上。
讲解
flex 容器有两条互相垂直的轴。主轴是 item 排队的那条轴,默认水平,就是第 1 课里的那个方向。交叉轴与主轴垂直1。在默认的 row 方向下,主轴从左到右,交叉轴从上到下。正式定义也是同一个意思:主轴是 flex item 沿其排布的首要轴,交叉轴与之垂直2。
现在是回报时刻。对齐属性有两个,每个只管一条轴:
所以在默认的 row 下:justify-content 左右移动 item,align-items 上下移动 item。规则就这么多。“justify”管主轴,“align”管交叉轴。当你伸手拿错属性时,元素就沿错误的轴移动,正是那个“想往下、却横着走”的 bug。
下图画了两条轴和两个属性。flex-direction 是 row。点击 justify-content 沿其分布 item 的那条轴。
一旦你能指出这两条轴,居中就不再是背下来的咒语。要居中一个元素,就在两条轴上同时对齐它:justify-content: center 沿主轴居中,align-items: center 沿交叉轴居中3。两个属性,各管一条轴。
下面的容器已经是 display: flex,并且有固定高度,两条轴都有活动空间。把卡片在两个方向上都居中。
如果你只设了 justify-content: center,卡片会左右居中但贴在顶部,因为你只处理了主轴。缺的那第二个属性,正是经典的“为什么水平居中了、垂直没居中?”时刻。
两个属性各自能取的值
点出轴只是一半功夫,另一半是在轴上点出位置。两个属性共用同一套核心词汇,而这些词说的是一条轴的两端,不是屏幕的边3:
flex-start/flex-end——对justify-content是主轴起点或主轴终点,对align-items是交叉轴起点或交叉轴终点。center——那条轴的正中间。space-between——把 item 摆好之后剩下的空间全部拿来,均匀分配在它们之间,所以第一个和最后一个会紧贴两端3。space-around——同样的思路,但每个 item 两侧各得半份空间,于是外侧的间距只有内侧的一半3。space-evenly——每一份空间都是整份,包括最外侧那两份3。
有两个值只属于 align-items,因为它们需要一条交叉轴才起作用。stretch 是 align-items 的初始值:这就是为什么 flex item 默认会跟最高的兄弟元素一样高,或者在容器设了高度时跟容器一样高3。而 baseline 让 item 按文字基线而不是按盒子边缘对齐,当一个大标题和一个小标签要读起来像坐在同一行上时,你要的就是它。
还有一个区别,它解释了为什么 justify-content 没有孪生兄弟:justify-items 在 flex 布局里会被忽略1。在主轴上,flex 把这些 item 当作一个整体处理,所以不存在“逐个 item 的主轴对齐属性”让你去找。这个不对称是真实存在的,值得记住,而不是日后再自己撞一次。
用 align-self 让某一个 item 特殊对待
align-items 是把所有 item 当一组来设对齐。当某一个 item 需要出列时,要用的属性是 align-self,它设在 item 上而不是容器上;它接受 align-items 的全部值,另外多一个 auto,意思是把决定权交回容器3。
注意这里立起来的规律:容器属性(justify-content、align-items)替一组做决定,item 属性(align-self,以及第 4 课的尺寸属性)替单个盒子做决定。当一个属性怎么都不生效时,先检查你是不是把容器属性写到了 item 上、或者反过来——相当大一部分 Flexbox bug 到这里就结案了。
出于上面说的原因,flexbox 里没有 justify-self。要沿主轴把某一个 item 推离其他人,惯用手法是auto 外边距:margin-left: auto 会把那一侧能吃的自由空间全部吃掉,导航栏就是这样把最后一个链接钉在右边、其余链接留在左边的3。
完整示例(跟着做)
你想把一个“Save”按钮钉在工具栏的右边缘,并在工具栏里垂直居中:
顺着轴走一遍:主轴是水平的(row 默认),所以 justify-content: flex-end 把 item 推向主轴终点,也就是右边缘。交叉轴是垂直的,所以 align-items: center 让 item 在 56px 的高度里上下居中。每个属性各自点名了它的轴和位置,没有一步是猜的。
你来试试(填空示例)
你想把一个徽标放到某个 flex 容器的左下角,容器是 display: flex 且设了高度。填上两个值:
答案:justify-content: flex-start(主轴起点是左边缘)和 align-items: flex-end(交叉轴终点是底部)。把每一行读成“哪条轴、哪一端”,角落自然就出来了:左来自主轴,下来自交叉轴。
小结 + 下节课预告
flex 容器有两条互相垂直的轴。justify-content 沿主轴对齐,align-items 沿交叉轴对齐。居中就是两条轴各做一次。但注意我们一直在说“默认水平”,这个默认由 flex-direction 设定,而下一课就要翻转它。一旦主轴从横着指变成竖着指,justify-content 就开始上下移动 item,很多人正是在这个意外上放弃的。我们把它变成显而易见的事。
Footnotes
-
MDN: Basic concepts of flexbox — https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Flexible_box_layout/Basic_concepts ↩ ↩2 ↩3 ↩4
-
W3C: CSS Flexible Box Layout Module Level 1 — https://www.w3.org/TR/css-flexbox-1/ ↩
-
MDN: Aligning items in a flex container — https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Flexible_box_layout/Aligning_items ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
Exercises
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.