目录
1. Flex布局
2. flex-grow
计算方式
3. flex-shrink
计算公式
4. flex-basis
5. 应用场景
6. 总结
1. Flex布局
Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性 flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为 0 1 auto
任何一个容器都可以用 Flex 进行布局(如果不会 flex 布局的可见阮老师的 Flex 布局教程),而且 Flex 是发生在父容器和子容器之间的布局关系的,那么父容器与子容器的关系是怎么样子的,又是怎么计算子容器所占用的空间的呢,怎么进行弹性布局的呢?
欲要解决上面的问题,首先得了解 flex-grow 和 flex-shrink 是怎么计算的?flex-basis 和 width 又有什么关系和区别?
接下来,我们先提出两个概念:剩余空间和溢出空间,具体是什么意思我们后面慢慢解释。
2. flex-grow
flex-grow属性在MDN上的定义是:
定义弹性盒子项(flex-item)的拉伸因子,默认值0”
传统的布局是子容器在父容器中从左到右进行布局,应用 flex 进行布局,那么父容器一定设置 display: flex
,子容器要“占有”并且“瓜分”父容器的空间,如何占有、瓜分的策略就是弹性布局的策略。这里就要解释到“剩余空间”的概念:
子容器在父容器的“主轴”上还有多少空间可以“瓜分”,这个可以被“瓜分”的空间就叫做剩余空间。
文字总是很抽象,举个例子就能理解剩余空间了,现在有如下的代码:
HTML 代码:
<body><div class="container"><div class="item a"><p>A</p><p> width:100</p><p>flex-grow:1</p></div><div class="item b"><p>B</p><p> width:150</p><p>flex-grow:2</p></div><div class="item c"><p>C</p><p> width:100</p><p>flex-grow:3</p></div></div>
</body>
CSS代码:
<style>.container {margin: 10px;display: flex;width: 500px;height: 200px;background-color: #eee;color: #666;text-align: center;}.item {height: 100px;}.item p {margin: 0;}.a {width: 100px;background-color: #ff4466;}.b {width: 150px;background-color: #42b983;}.c {width: 100px;background-color: #61dafb;}</style>
展示的效果如下(最后那个框是截图的时候的标注,不是展示出来的效果):
这就需要用到flex-grow
属性了,flex-grow
定义子容器的瓜分剩余空间的比例,默认为 0
,即如果存在剩余空间,也不会去瓜分。
flex-grow
例子,将上面的例子改成如下代码:
HTML 代码(代码只增加了 flex-grow 的说明,没有其他结构的变动):
<body><div class="container"><div class="item a"><p>A</p><p> width:100</p><p>flex-grow:1</p></div><div class="item b"><p>B</p><p> width:150</p><p>flex-grow:2</p></div><div class="item c"><p>C</p><p> width:100</p><p>flex-grow:3</p></div></div>
</body>
CSS 代码(给每个子容器增加了 flex-grow):
<style>.container {margin: 10px;display: flex;width: 500px;height: 200px;background-color: #eee;color: #666;text-align: center;}.item {height: 100px;p {margin: 0;}}.a {width: 100px;flex-grow: 1;background-color: #ff4466;}.b {width: 150px;flex-grow: 2;background-color: #42b983;}.c {width: 100px;flex-grow: 3;background-color: #61dafb;}</style>
结果如下:
最初,我们发现,子容器的宽度总和只有 350px,父容器宽度为 500px,那么剩余空间就出现了,为 150px。当设置了 flex-grow
之后, A,B,C三个子容器会根据自身的 flex-grow
去“瓜分”剩余空间。
在这里我们总结为 flex-grow 属性决定了子容器要占用父容器多少剩余空间。
计算方式
确定总的
flex-grow
值:首先,你需要计算所有Flex项目的flex-grow
值的总和。这个总和将用于确定每个项目应该获得的额外空间的比例。然后,对于每个项目,计算其应该获得的额外空间。这可以通过以下步骤完成:
- 将该项目的
flex-grow
值除以总的flex-grow
值。- 将得到的比例乘以容器的剩余空间。
最后,将计算出的额外空间加到每个项目的原始大小上,得到该项目的最终大小。
以 例子进行说明:
考虑是否可以把 flex-grow 设置的值小于 1,而且 flex-grow 的和也小于 1 呢?只要把上面公式的分母(flex-grow 的和)设置为 1 就好啦!
3. flex-shrink
说完 flex-grow,我们知道了子容器设置了 flex-grow 有可能会被拉伸。那么什么情况下子容器被压缩呢?考虑一种情况:如果子容器宽度超过父容器宽度,即使是设置了 flex-grow,但是由于没有剩余空间,就分配不到剩余空间了。这时候有两个办法:换行和压缩。由于 flex 默认不换行,那么压缩的话,怎么压缩呢,压缩多少?此时就需要用到 flex-shrink 属性了。
flex-shrink属性在MDN上的定义是:
指定了 flex 元素的收缩规则,默认值是 1
此时,剩余空间的概念就转化成了“溢出空间”
计算公式
-
计算总的可压缩量:
- 这是所有子元素可以缩小的总量,计算方法是将每个子元素的基础大小乘以其
flex-shrink
值,然后求和。 - 公式:总压缩 = 子元素1基础大小 × 子元素1的
flex-shrink
值 + 子元素2基础大小 × 子元素2的flex-shrink
值 + ...
- 这是所有子元素可以缩小的总量,计算方法是将每个子元素的基础大小乘以其
-
计算每个子元素的压缩比例:
- 这是每个子元素的可压缩量与其总压缩量的比例。
- 公式:子元素压缩比例 = (子元素基础大小 × 子元素的
flex-shrink
值) / 总压缩
-
计算每个子元素的实际压缩量:
- 这是基于溢出空间和子元素的压缩比例来计算的。
- 公式:子元素实际压缩量 = 溢出空间 × 子元素压缩比例
-
计算每个子元素的实际宽度:
- 这是子元素的基础宽度减去其实际压缩量。
- 公式:子元素实际宽度 = 子元素基础宽度 - 子元素实际压缩量
举例说明:
<!DOCTYPE html>
<html><head><style>.container {margin: 10px;display: flex;width: 500px;height: 200px;background-color: #eee;color: #666;text-align: center;}.item {height: 100px;}.item p {margin: 0;}.a {width: 300px;flex-grow: 1;flex-shrink: 1;background-color: #ff4466;}.b {width: 150px;flex-shrink: 2;background-color: #42b983;}.c {width: 200px;flex-shrink: 3;background-color: #61dafb;}</style>
</head><body><div class="container"><div class="item a"><p>A</p><p> width:300</p><p>flex-shrink: 1</p></div><div class="item b"><p>B</p><p> width:150</p><p>flex-shrink: 2</p></div><div class="item c"><p>C</p><p> width:200</p><p>flex-shrink: 3</p></div></div></body></html>
结果如下:
同样,如果出现flex-shrink总和小于1?那么计算溢出空间(收缩总和)的结果有所变化。比如:shrink设置为0.1, 0.2, 0.3, 原溢出空间为200,实际溢出空间:200 * (0.1 + 0.2 + 0.3)/ 1 = 120。
注意:如果子容器没有超出父容器,设置 flex-shrink 无效
4. flex-basis
MDN定义:指定了 flex 元素在主轴方向上的初始大小
一旦 flex item 放进 flex 容器,并不能保证能够按照 flex-basis 设置的大小展示。浏览器会根据 flex-basis 计算主轴是否有剩余空间。既然是跟宽度相关,那么 max-width,min-width,width 和 box 的大小优先级是怎么样的。
举例说明:
<!DOCTYPE html>
<html><head><style>.container {margin: 10px;display: flex;width: 500px;height: 200px;background-color: #eee;text-align: center;line-height: 100px;color: #666;}.item {width: 100px;height: 100px;}.a {flex-basis: 200px;background-color: #ff4466;}.b {max-width: 50px;flex-basis: 150px;background-color: #42b983;}.c {background-color: #61dafb;}</style>
</head><body><div class="container"><div class="item a">A</div><div class="item b">B</div><div class="item c">C</div></div></body></html>
结果如下:
上面的例子可以通过最终元素的宽度看出几个属性的优先级关系:
max-width/min-width > flex-basis > width > box
5. 应用场景
- 一种很常见的布局:当内容区域高度不够的时候,footer仍然需要固定在底部。这时候,我们可以给main使用flex-grow: 1,使它自动填满剩余空间。
2 . 在我们开发一种常见的表单组件的时候,使用flex布局,可以使输入框占满剩余空间。
而大部分场景下我们不希望元素被压缩,所以flex-shrink通常设置为0。
6. 总结
最后,我们需要注意的是:
- flex items 总和超出 flex 容器,会根据 flex-shrink 的设置进行压缩
- 如果有剩余空间,如果设置 flex-grow,子容器的实际宽度跟 flex-grow 的设置相关。如果没有设置flex-grow,则按照 flex-basis 展示实际宽度
flex 1
在CSS中,flex
是 flex-grow
, flex-shrink
, 和 flex-basis
这三个属性的简写形式。当你看到 flex: 1;
这样的声明时,它实际上是设置了以下三个属性:
flex-grow: 1;
- 表示如果容器内有多余的空间,这个元素会按照比例增长来占据这些空间。flex-shrink: 1;
- 表示如果容器空间不足,这个元素会按照比例缩小来适应容器。flex-basis: 0;
- 表示在分配多余空间之前,元素的默认大小是0。
简而言之,flex: 1;
会让元素在容器中尽可能地扩展以填充可用空间,同时在需要时也能缩小。