时间:2021-07-01 10:21:17 帮助过:51人阅读
最近遇到个问题: flex:1;跟 flex:1 1 0;是否等价。按照我之前对W3C属性值语法的理解, flex:1;应该是 flex:1 1 auto;的缺省写法,剩下的两个 flex-shrink和 flex-basis的坑应该分别对应 1和 auto。嗯,如果我没记错的话,简写属性(shorthand)有个特性:对于缺省值会重置为对应的单个属性的初始值(详情请参看《CSS权威指南第三版》P130)。这里的 flex-shrink和 flex-basis就是缺省的单个属性。可是常规测试(弹性子项未填充内容)都不能让人明显感知到 flex:1;跟 flex:1 1 0;的区别。那么问题来了:How Can We Feel The Difference?
首先,确定我们要做什么?通过实验了解flex的缺省auto跟0有何区别。
然后,给出代码(可以去我的 Github上找到名为shorthand_flex_test的两个文件查看源代码):
.contain { background: #aec; height: 100px; display: flex; justify-content: space-around;/*设置主轴方向均分对齐*/ flex-flow: row wrap;/*设置正常水平排列*/ align-items: stretch;/*设置所有弹性子项拉伸到弹性容器高度*/}.item { border: 3px solid rgba(0,0,0,.2); padding: 10px; background: #eac; color: #fff; font-size: 2em; font-weight: bold; text-align: center;}
效果图:
接下来,看实验。
给.item设置 flex:1;,效果图如下:
给.item设置 flex:1 1 auto;,效果图:
WTF?不对!
先别急,F12看下设置 flex:1;时devtool窗口里的计算值
再看看设置 flex:1 1 auto;时的计算值(这句是废话,请自动省略)
小结:原来缺省的时候不是取的单项的初始值啊( flex-shrink:1和 flex-basis:auto)。那么这个 0%是不是就等价于 0呢?
图还是这样的,可是计算值不一样啊,如下
小结:其实百分比的计算值是以父类容器的宽度为基数计算的,而长度值 0直接取值不用再计算,但是 0%和 0的最终计算值都是 0px。
所以说开始的疑问得到解答了: flex:1;跟 flex:1 1 0;的视觉效果和最终计算值是一样的,只不过是计算过程不同。
第一种: flex:initial;等价于 flex:0 1 auto;,也等价于 flex:0 auto;
给.item设置 flex:initial;
计算值
小结:这里是 auto自适应得到的 10%。这个属性声明得到的效果就是使得弹性子项在有多余空间的时候不拉伸,在空间不足时收缩到最小的宽度/高度(由主轴方向决定具体的计算基数)。这里的宽度/高度可能涉及到弹性子项内部的文本内容,内容的有无使得 auto跟另一个 flex-basis的属性 content有差异,后面讲。另外,当设置为这个属性值的时候,弹性容器上设置的主轴方向对齐效果和 margin:auto;居中效果才能生效。
第二种: flex:auto;等价于 flex:1 1 auto;
给.item设置 flex:auto;
计算值
小结:这使得弹性子项在有多余空间时拉伸,在空间不足时收缩。这时候弹性子项才有完整的弹性效果,而当多个弹性子项设置不同的 flex属性声明时,任何多余空间都将被设置了 auto属性值的弹性子项“吸收”掉。
第三种, flex:none等价于 flex:0 0 auto;
给.item设置 flex:none
计算值
小结:这使得弹性子项完全失去弹性效果。效果跟设置 auto属性值差不多,但是一旦内容溢出弹性容器,这里的弹性子项是不会收缩的。
第一步,我们来跟 initial的等价值做个对照。 initial的就不贴了,Part1的第一种里有。直接看 flex:0 1 content;
计算值
分析:什么情况?! flex的计算值呢?前面的 none都会有计算值的,这里竟然不见了!稍等,可不可以这样理解,在设置 content的时候,前面两个值可以忽略?
第二步,设置 flex:content;
计算值
分析:果然是一毛一样的。BUT,WHY? content到底是干啥子的?
标准里说这个属性值设置会使得弹性子项的宽度/高度直接由其中的内容决定。哦~,难怪对照效果中明显是上面那组的弹性子项“们”是被内容撑开了的。
でも、这岂不是跟不设置 flex属性没两样了!书读少勿欺我!保险起见,我只能开“大招”了:
-webkit-flex: content; -moz-flex: content; -ms-flex: content; -o-flex: content; flex: content;
计算值里还是找不到 flex的影子
第三步,再在第二步的“大招”基础上加个 width:100px;
计算值里还只没影儿
分析:这里给每个弹性子项设置了固定宽度(因为这水平轴就是主轴),因为没有 flex属性的伸展因子 flex-grow和收缩因子 flex-shrink的影响,每个弹性子项都“老老实实的”按照 justify-content: space-around的指令水平对齐了(嘴上说着不要“身体”还是挺老实的嘛,啧啧)。
好吧,只能承认, content是个无效的属性值。对!它并不是属性值。好大一个玩笑(轻点,别打脸)。它只是表示弹性子项的宽度/高度由内容决定,即被内容撑开。而这个撑开的宽度/高度则作为伸展因子和收缩因子的基数进行相应弹性变化的计算。
第一步,先看不设置 flex属性时上面对照实验中上面一组的数据(记得“关了” width),从左至右:
可以看到第一个no1和第三个no3的宽度是相同的84.297,第二个是290.875。这里要注意因为 box-sizing初始值是 content-box,所以内容区宽就是 width的取值,边距边框都不用管。
第二步,设置一个伸展因子 flex:1 1 auto;这里必须设置 flex-basis:auto;因为缺省后就是 flex-basis:0%;了,相当于以撑开的宽度/高度作为的基数置零了。效果图就不上了,对应前面的 flex:auto;,下面是计算值
可以看到这次的第一个no1和第三个no3的宽度是126.813,第二个是333.391。然后让我们搬出伸展因子的计算公式:
flex-basis + flow-grow / sum( flow-grow ) * remain
这里的 flow-grow指的就是 flex-flow方向上的伸展因子的数值,而由于设置了 flex-basis:auto;主轴的基数 flex-basis的计算值应该就是第一步的数据84.297、290.875和84.297; remain则是容器总宽度减去第一步中的所有宽度总和的结果:
665 - ( 84.2969 + 290.875 + 84.2969) - (10 + 3)\*2\* 3 = 127.5312
这里因为是算的弹性容器内的区域所以要把内边距和边框都加上,另外之前在盒模型里显示的84.297不是精确值,最下面的计算值清单里的精确值是84.2969,以免引起后面结果错误。
最后套入公式:
第二部中第一个和第三个弹性子项的宽:
84.2969 + ( 1 / 3 ) \* 127.5312 = 126.8073(这里跟126.813很接近,但是我找不出那里算漏了的,有指导的朋友麻烦告知,谢谢)
第二个弹性子项的宽:
290.875 + (1 / 3 ) \* 127.5312 = 333.3854(待查错)
这一部分先到这里吧。花了我好久时间,好晚了。
flex的缺省值并非是单一属性的初始值,并且还有常用的简写属性值 initial、 auto和 none;当弹性子项没有设置固定宽度(对于水平的情况,也就是宽度本身是 auto的)时, flex-basis如果也是 auto,那么 flex-basis的使用值就是弹性子项的内容本身撑起来的宽度(对于水平的情况)
操作系统:window 7 ultimate 64bit
chrome内核版本:45.0.2454.101
编辑器:Sublime Text 3
CSS Flexible Box Layout Module Level 1
flex | CSS-Tricks
关于弹性长度计算的描述: https://drafts.csswg.org/css-flexbox/#resolve-flexible-lengths
在查找资料过程中,发现一些不错的东西,分享加收藏一下。
不明觉厉的网站和文章: http://ptb2.me/
CSS Flexbox试验场: http://vagor.cc/demo/flexbox-demo/index.html
Flexbox-推陈出新: https://css-tricks.com/old-flexbox-and-new-flexbox/
先这样了,为了发完这文章熬夜了。熊猫君思密达。
对了代码可以去我的 Github上找,说完了。
再补一点信息,一定不要忘了标注的文档开篇说的: