在 flex 之前,如果不是专门去搜索相关的解决方案,一般人几乎想不出非常灵活的三(多)栏等高布局方案,而即使看了解决方案,很多人也会大呼奇技淫巧。 不得不感慨在 flex 之前 CSS 的布局功能之弱:基本只能使用一些并非为布局而设计的属性来实现想要的布
在 flex 之前,如果不是专门去搜索相关的解决方案,一般人几乎想不出非常灵活的三(多)栏等高布局方案,而即使看了解决方案,很多人也会大呼奇技淫巧。
所以我决定写这一篇文章,把 flex-grow 与 flex-shrink 的详细计算方式讲清楚。
其中 section 元素的宽度将会像 block 元素一样尽量的宽,对外面的元素来说,它的行为很像一个 block 块。三个元素会从左往右占据父元素的空间(这很显然)。左右侧边栏的宽度都是 200px,中间 .content 元素的宽度将会占据 section 元素的剩余宽度。 另外,section 的高度会自动被最高的一个子元素撑开,同时其它子元素的高度也会被拉到跟 section 元素一样高,而如果给 section 元素设置了高度,而所有子元素的高度设置为 auto ,所有的子元素也都会自动跟父元素一样高,这简直就是在传统布局中做梦都想要的功能! 总之,在高度方面,flex 的表现是相当符合直觉的。 另外,如果不给 flex 子元素设置宽度和 flex-grow,它会尽量的窄。 flex-grow 的计算方式 上面 demo 中最值得注意的是 .content 元素的 flex-grow 属性,设置为 1 它就可以占满水平剩余空间。这也是本文的重点:讲清 flex-grow 与 flex-shrink 属性的详细计算方式。 flex-grow 属性决定了父元素在空间分配方向上还有剩余空间时,如何分配这些剩余空间。其值为一个权重(也称扩张因子),默认为 0(纯数值,无单位),剩余空间将会按照这个权重来分配。 比如剩余空间为 x,三个元素的 flex-grow 分别为 a,b,c。设 sum 为 a + b + c。那么三个元素将得到剩余空间分别是 x a / sum, x b / sum, x * c / sum,是为权重也。 举个例子: 父元素宽度 500px,三个子元素的 width 分别为 100px,150px,100px。 于是剩余空间为 150px
三个元素的 flex-grow 分别是 1,2,3,于是 sum 为 6
150 * 1 / 6 = 25px
100px + 25px = 125px 然而!不止这些,还有一种情况: 当所有元素的 flex-grow 之和小于 1 的时候(注意是 1,也就是说每个元素的 flex-grow 都是一个小数如 0.2 这样的),上面式子中的 sum 将会使用 1 来参与计算,而不论它们的和是多少。也就是说,当所有的元素的 flex-grow 之和小于 1 的时候,剩余空间不会全部分配给各个元素。 实际上用来分配的空间是 sum(flex-grow) / 1 * 剩余空间,这些用来分配的空间依然是按 flex-grow 的比例来分配。 还是上面一个例子,但是三个元素的 flex-grow 分别是 0.1,0.2,0.3,那么计算公式将变成下面这样:
150 * 0.1 / 1 = 15px 三个元素的最终宽度分别为:
100px + 15px = 115px 如上所述即是 flex-grow 的计算方式。 另外,flex-grow 还会受到 max-width 的影响。如果最终 grow 后的结果大于 max-width 指定的值,max-width 的值将会优先使用。同样会导致父元素有部分剩余空间没有分配。 flex-shrink 的计算方式 前文已经说到,flex 几乎一次性解决了前端布局的所有问题。 那么既然可以在空间有多余时把多余空间分配给各个子元素,当然也可以在空间不够时让各个子元素收缩以适应有限的空间了。 这就是 flex-shrink 属性的作用。 你可能会觉得 flex-shrink 的计算方式跟 flex-grow 很类似,然而事情并没有这么简单。 flex-shrink 属性定义空间不够时各个元素如何收缩。其值默认为 1。很多文章对此基本是一笔带过:“flex-shrink 属性定义了元素的收缩系数”,根本就不说它具体是怎么计算的。 flex-shrink 定义的仅仅只是元素宽度变小的一个权重分量。 每个元素具体收缩多少,还有另一个重要因素,即它本身的宽度。 举个例子: 父元素 500px。三个子元素分别设置为 150px,200px,300px。 三个子元素的 flex-shrink 的值分别为 1,2,3。 首先,计算子元素溢出多少:150 + 200 + 300 - 500 = -150px。 那这 -150px 将由三个元素的分别收缩一定的量来弥补。 具体的计算方式为:每个元素收缩的权重为其 flex-shrink 乘以其宽度。 所以总权重为 1 150 + 2 200 + 3 * 300 = 1450 三个元素分别收缩:
150 1(flex-shrink) 150(width) / 1450 = -15.5 三个元素的最终宽度分别为:
150 - 15.5 = 134.5 同样,当所有元素的 flex-shrink 之和小于 1 时,计算方式也会有所不同: 此时,并不会收缩所有的空间,而只会收缩 flex-shrink 之和相对于 1 的比例的空间。 还是上面的例子,但是 flex-shrink 分别改为 0.1,0.2,0.3。 于是总权重为 145(正好缩小 10 倍,略去计算公式)。 三个元素收缩总和并不是 150px,而是只会收缩 150px 的 (0.1 + 0.2 + 0.3) / 1 即 60% 的空间:90px。 每个元素收缩的空间为:
90 0.1(flex-shrink) 150(width) / 145 = 9.31 三个元素的最终宽度分别为:
150 - 9.31 = 140.69 当然,类似 flex-grow,flex-shrink 也会受到 min-width 的影响。 总结
虽然上面的公式看起来很复杂,其实计算过程还是比较简单的:如果所有元素的 flex-grow/shrink 之和大于等于 1,则所有子元素的尺寸一定会被调整到适应父元素的尺寸(在不考虑 max/min-width/height 的前提下),而如果 flex-grow/shrink 之和小于 1,则只会 grow 或 shrink 所有元素 flex-grow/shrink 之和相对于 1 的比例。 |
2021-04-14
2021-04-29
2018-01-07
2022-06-10
2021-09-30