第 4 课:剩余空间的分配
本课目标:
- 解释
flex-basis、flex-grow、flex-shrink各自控制什么。- 预测
flex-grow如何划分自由空间(不是总宽度)。- 读懂
flex简写,并知道flex: 1展开成什么。先修条件:第 1-3 课(两条轴、
justify-content、align-items、flex-direction) | 上一篇 << 03 | 下一篇 05 >>
“flex: 2 应该是两倍宽”,以及为什么通常不是
早晚有一天,你会给一个 item 写 flex: 1、给另一个写 flex: 2,然后期待第二个正好是两倍宽。有时看起来对,更多时候不对,而且你说不出为什么。原因是这些属性划分的不是 item 的宽度,而是 item 尚未占用的剩余空间。漏掉“剩余”这一个词,你设的每个比例都显得随机。这一课把“到底在分什么”钉死。
讲解
有三个属性控制 flex item 沿主轴的尺寸。一个一个来。
flex-basis 是 item 在任何自由空间分配之前的起始尺寸1。把它理解成“进入谈判之前,我想要多大”。默认值 auto 下,起始尺寸来自 item 自己的宽度或内容。
flex-grow 是一个增长因子:当有多余空间时,它决定 item 拿走多少正自由空间1。机制是比例,不是宽度。浏览器把每个 item 的增长因子加总,用总数去除自由空间,再把各自的份额分给每个 item1。所以 flex-grow: 2 挨着 flex-grow: 1,意思是第一个 item 拿到自由空间的三分之二,不是容器的三分之二。
flex-shrink 是镜像:当 item 总尺寸超出、出现负自由空间需要扣除时的收缩因子1。收缩因子越高,意思是“超支时让出更多宽度”。有一个让收缩显得难以预测的细节:扣除量还会按每个 item 的基础尺寸加权,所以在收缩因子相同的情况下,宽的 item 比窄的 item 让出更多宽度1。
“自由空间”这个词就是整课的核心。自由空间是把每个 item 的基础尺寸都预留之后剩下的部分。grow 和 shrink 永远只作用在这块剩余上。
这三个属性你很少分开设。flex 简写把它们合在一起:flex: 2 1 auto 表示 flex-grow: 2、flex-shrink: 1、flex-basis: auto,而且指南推荐用简写代替单独的属性2。常见的一行 flex: 1 展开为 flex: 1 1 0:grow 1、shrink 1、basis 0。因为 basis 是 0,每个 item 都从零起步,整条行都成了自由空间,所以给几个 item 都设 flex: 1 会让它们无视内容、真正等宽1。
下面的导航栏有 logo、搜索框和按钮。现在搜索框只有占位文字那么宽。让它长开、填满中间的空白,同时 logo 和按钮保持自然尺寸。
只有搜索框拿到了增长因子,所以只有它认领自由空间。logo 和按钮的 grow 是 0,所以它们保持内容需要的大小不变。这就是日常的“一个弹性元素、几个固定元素”导航模式。
完整示例(跟着做)
一个三栏布局,中间栏的弹性是两侧的两倍:
因为三个都用 flex-basis: 0,整个宽度都是自由空间,按增长因子 1 : 2 : 1 划分。因子总数是 4,所以每个 .side 拿到宽度的四分之一,.main 拿到一半。这里 flex: 2 确实意味着“两倍于一侧”,但只因为 basis 是 0,它把整条行都变成了自由空间。把 basis 改成 auto,比例就会作用在剩余空间上了。
你来试试(填空示例)
你想要一个固定 240px 的侧边栏,和一个吃掉其余全部空间的内容区。填上两个 flex 简写:
答案:.sidebar { flex: 0 0 240px; }(grow 0、shrink 0、basis 240px,它原地不动)和 .content { flex: 1; }(grow 1,吸收全部自由空间)。把每个简写读成“grow / shrink / basis”,意图一目了然:侧边栏拒绝伸缩,内容区拿走剩下的。
小结 + 下节课预告
flex-basis 设定 item 的起始尺寸;flex-grow 和 flex-shrink 按各自因子的比例划分正或负的自由空间;flex 简写把三者打包,flex: 1 等于 1 1 0。到目前为止一切都假设 item 只有一行。最后一课我们用 flex-wrap 让 item 换到多行、用 gap 拉开间距,然后你从零搭一个真实的响应式导航栏和卡片行。
Footnotes
-
MDN: Controlling ratios of flex items along the main axis — https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Flexible_box_layout/Controlling_flex_item_ratios ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
CSS-Tricks: A Complete Guide to Flexbox — https://css-tricks.com/snippets/css/a-guide-to-flexbox/ ↩