一文详解三个 flex 属性对元素的影响
在开发的时候经常用 flex 这个属性作用于弹性盒子的子元素,例如:flex:1或者flex: 1 1 auto,那么这个属性到底控制了元素怎么的行为呢?flex:1又究竟是什么含义呢?让这篇文章带你彻底了解 flex 属性吧!【推荐学习:css视频教程】
首先我们需要了解,flex 是三个属性 flex-grow 、flex-shrink 、flex-basis的简写,可以使用一个、两个、或者三个值指定 flex 属性。具体语法可以参考MDN-flex
接下来我们逐一拆解这三个属性对元素的影响
flex-basis
flex-basis 定义了空间分配发生之前初始化 flex 子元素的尺寸,属性默认值 auto; flex 子元素未伸张和收缩之前,它的大小是多少。
如果 flex-basis 设置为 auto , 浏览器会先检查 flex 子元素的主尺寸是否设置了 flex 子元素的初始值。
比如说你已经给你的 flex 子元素设置了 150px 的宽,则 150px 就是这个 flex 子元素的 flex-basis;如果没有设置,则 auto 会解析为其内容的大小。这个例子中,给第一个元素设置宽度150px,第二、三个元素不设置宽度。
:first-child { width: 150px;}
效果如下:
如果你想 flexbox 完全忽略 flex 子元素的尺寸就设置 flex-basis 为 0。这样就算元素一设置了宽度,它最终的宽度也是内容宽度。
正负自由空间
在介绍剩下两个属性前先看两个概念 positive free space 正向自由空间和 negative free space反向自由空间:
那么用什么属性分配正负自由空间呢?
flex-grow
初始状态:我们给三个元素都设定宽度,并且总和不大于主轴宽度
.flex-grow-father { width: 500px; div:nth-child(1) { width: 50px; } div:nth-child(2) { width: 100px; } div:nth-child(3) { width: 150px; }}
增加的宽度计算方法:假设元素的 flex-grow 值为 x,正向自由空间宽度为l,则每个元素增加的宽度=xx的总和∗l\frac{x}{x的总和}*lx的总和x∗l,元素最终宽度 = 元素初始宽度+增加的宽度元素初始宽度 + 增加的宽度元素初始宽度+增加的宽度;
.with-same-flex-grow { * { flex-grow: 1; }}
效果如下:
本例中第一个元素宽度的计算 11+1+1∗200+50=116.67px\frac{1}{1+1+1}*200 + 50 = 116.67px1+1+11∗200+50=116.67px;
第二个元素宽度宽度计算 11+1+1∗200+100=166.67px\frac{1}{1+1+1}*200 + 100 = 166.67px1+1+11∗200+100=166.67px;
第三个同理为216.67px216.67px216.67px
.with-different-flex-grow { div:nth-child(1) { flex-grow: 2; } div:nth-child(2) { flex-grow: 1; } div:nth-child(3) { flex-grow: 1; }}
效果如下:
本例中第一个元素宽度的计算22+1+1∗200+50=150px\frac{2}{2+1+1}*200 + 50 = 150px2+1+12∗200+50=150px;
第二个元素宽度的计算12+1+1∗200+100=150px\frac{1}{2+1+1}*200 + 100 = 150px2+1+11∗200+100=150px;
第三个同理是200px200px200px
.average { * { /* flex: 1 1 0; */ flex-basis: 0; flex-grow: 1; }}
效果如下:
flex-shrink
flex-shrink 属性指定了 flex 元素的缩小值,默认值为 1; 它确定在分配 negative free space 时,flex 子元素相对于 flex 容器中其余 flex 子元素收缩的程度。默认值 1。用于减少盒子空间使盒子适应容器而不溢出(为了避免 border 干扰去掉边框)
我们给三个元素都设定宽度,并且总和大于主轴宽度;这里我们将元素的flex-shrink值设置为 0 (元素宽度不变,不需要吸收溢出的宽度),目的是观察一下反向自由空间。
.flex-shrink-wrapper { display: flex; div:nth-child(1) { width: 100px; background: gold; } div:nth-child(2) { width: 200px; background: tan; } div:nth-child(3) { width: 300px; background: gold; }}.zero { * { flex-shrink: 0; }}
吸收的宽度计算:假设每个 flex-shrink 的值为 xnx_nxn,元素的初始宽度为 lnl_nln,反向自由空间为LLL那么每个元素吸收的宽度为: xn∗lnx1∗l1+...+xn∗ln∗L\frac{x_n*l_n}{x_1*l_1+...+x_n*l_n}*Lx1∗l1+...+xn∗lnxn∗ln∗L
.with-same-flex-shrink { * { flex-shrink: 1; }}
这时第一个元素的吸收宽度为:1∗1001∗100+1∗200+1∗300∗100=16.67px\frac{1*100}{1*100+1*200+1*300}*100 = 16.67px1∗100+1∗200+1∗3001∗100∗100=16.67px,最终元素宽度为 100−16.67=83.37px100-16.67=83.37px100−16.67=83.37px
这时第一个元素的吸收宽度为:1∗2001∗100+1∗200+1∗300∗100=33.33px\frac{1*200}{1*100+1*200+1*300}*100 = 33.33px1∗100+1∗200+1∗3001∗200∗100=33.33px,最终元素宽度为 200−33.33=166.67px200-33.33=166.67px200−33.33=166.67px
这时第一个元素的吸收宽度为:1∗3001∗100+1∗200+1∗300∗100=50px\frac{1*300}{1*100+1*200+1*300}*100 = 50px1∗100+1∗200+1∗3001∗300∗100=50px,最终元素宽度为 300−50=250px300-50=250px300−50=250px
.with-different-flex-shrink { div:nth-child(1) { flex-shrink: 1; } div:nth-child(2) { flex-shrink: 2; } div:nth-child(3) { flex-shrink: 0; }}
这时第一个元素的吸收宽度为: 1∗1001∗100+2∗200∗100=20px\frac{1*100}{1*100+2*200}*100 = 20px1∗100+2∗2001∗100∗100=20px,最终元素宽度为 100−20=80px100-20=80px100−20=80px
这时第二个元素的吸收宽度为:2∗2001∗100+2∗200∗100=80px\frac{2*200}{1*100+2*200}*100 = 80px1∗100+2∗2002∗200∗100=80px,最终元素宽度为 200−80=120px200-80=120px200−80=120px
这时第三个元素的 flex-shrink 值为 0,不吸收宽度,最终元素宽度即为元素本身的宽度 300px300px300px
flex 的简写值
一般我们很少见上述属性单独使用,都是用flex这一个简写属性来表述元素的伸缩。
Flex 简写形式允许你把三个数值按这个顺序书写 flex-grow,flex-shrink,flex-basis。以下是常见的几种取值:
flex: 的应用:
两栏布局
.two-grid-wrapper { display: flex; margin-top: 20px; height: 200px; .left { width: 200px; background-color: gold; } .right { flex: 1; background-color: tan; }}
效果如下:左侧宽度不变,右侧自适应
三栏布局
.three-grid-wrapper { display: flex; margin-top: 20px; height: 200px; .left { width: 200px; background-color: gold; } .right { width: 200px; background-color: gold; } .center { flex: 1; background-color: tan; }}
效果如下:左右宽度不变,中间自适应
PS.flex 子元素没有 positive free space 就不会增长;没有 negative free space 就不会缩小。
结束语
学习八股文的时候发现自己对flex布局很不熟悉,基本概念都说不上来,只会无脑用,于是去学习,然后就诞生了这篇文章。欢迎指正。
(学习视频分享:web前端)