低版本 IE 一直是前端开发的黑洞,从今年起公司终于放弃了 IE 这个低能儿。最近可以大刀阔斧地使用一些 CSS3 新属性了,从简单的了解到使用,还得花一段时间好好琢磨一下。
flex 属性是 flex-grow
, flex-shrink
和 flex-basis
三个属性的简写形式,必须应用在弹性盒模型(设置了 display: flex)元素的子元素上,否则 flex 属性是不起作用的。
语法格式如下:
flex: <flex-grow> <flex-shrink> <flex-basis>
flex-basis
flex-basis 指明了元素的宽度,相当于 width 这个属性。如果flex-basis 和 width 两个属性同时存在,则 flex-basis 会覆盖 width 的值。
如果 flex-basis 设为 auto,则 width 属性生效。
1 | <div class="flex-box"> |
1 | .flex-box { |
在上面这个的结构里,item-1
元素设置了 width 为 200px,但是 flex-basis 设置为 100px 覆盖了 width 的值。实际显示出的宽度也为 100px。
flex-grow
该属性决定了当父元素宽度大于子元素宽度之和时,子元素的宽度该如何改变。
flex-grow 默认值为 0
flex-grow
的默认值为 0,说明子元素在任何情况下宽度都不变。就像上边的例子一样,子元素将保持 flex-basis
中设置的宽度不变,而不会进行放大。
flex-grow 大于 0
flex-grow
如果不为 0,则表示当父元素宽度大于子元素宽度之和时,子元素宽度将增加,而增加多少则取决于 flex-grow
的值。
仍以上边的例子为例,父元素宽为 400px,两个子元素宽度分别为 200px 和 100px,剩余 100px (400px - 200px - 100px)。如果子元素的 flex-grow
的值大于 0,则会对剩余的 100px 进行分割。
如果 item-1
设置 flex-grow
为 1,item-2
设置 flex-grow
为 2,那么两个子元素分别按照 1:2 的比例对剩余宽度进行分割。
item-1
将得到剩余的宽度为: 100px 1/(1+2) = 33.3pxitem-2
将得到剩余的宽度为: 100px 2/(1+2) = 66.7px
最终,item-1
的总宽度为:100px + 33.3px = 133.3pxitem-2
的总宽度为:200px + 66.7px = 266.7px
1 | .flex-box { |
只有设置 flex-grow
属性大于 0 的元素会对剩余空间进行分割,例如 item-1
设为 1, item-2
默认为 0。则 item-1
的最终宽度为 100px + 100px(剩余宽度) = 200px,而 item-2
则保持原大小不变。
flex-shrink
该属性决定了当父元素宽度小于子元素宽度之和时,子元素的宽度该如何改变。
flex-shrink 默认值为 1
flex-shrink
的默认值为 1 而不是 0!如果所有子元素都采用默认值 1,那么将按照子元素的宽度比例等比缩小。
flex-shrink 为 0
flex-shrink
等于 0 时,子元素宽度不变。
在下面这个例子中,item-1
的宽度为 300px,item-2
的宽度为 200px,尽管两个子元素宽度之和超过了父元素的 400px 宽度,但子元素均设置了 flex-shrink: 0
,所以宽度保持不变,结果仍然会超出父元素的宽度。
1 | .flex-box { |
flex-shrink 大于 0
flex-shrink
如果大于 0,则表示当父元素宽度小于子元素宽度之和时,子元素宽度将减小到与父元素相同,而每个子元素减小多少则取决于 flex-shrink
的值。
仍以上边的例子为例,父元素宽为 400px,两个子元素宽分别为 300px 和 200px,超出父元素 100px (300px + 200px - 400px)。如果子元素的 flex-shrink
的值大于 0,则会对超出的 100px 进行分割。
如果 item-1
设置 flex-shrink
为 3,item-2
设置 flex-shrink
为 2,那么按照刚才的 flex-grow
计算原则,是不是两个子元素像下面这样,分别按照 3:2 的比例对超出部分进行缩小呢?
item-1
缩小: 100 3/(3+2) = 60px
item-2
缩小: 100 2/(3+2) = 40px
最终,item-1
的总宽度为:200px - 60px = 140pxitem-2
的总宽度为:300px - 40px = 260px
答案是:并不是!!!!
flex-shrink
的值谜之诡异,因为它不仅与本身的值有关,还与元素的宽度有关!!!!
正确的计算方法是这样的:
item-1
缩小: 100px [ 3\200px / (3*200px + 2300px)] = 50px
item-2
缩小: 100px [ 2*300px / (3*200px + 2*300px)] = 50px
最终,item-1
的总宽度为:200px - 50px = 150pxitem-2
的总宽度为:300px - 50px = 250px
这里比较难理解的是 3*200px / (3*200px + 2*300px),你可以将 200 和 300 想象为权重,各子元素的“地位”并不是平等的(平等时,直接使用 3/(3+2) 即可),当子元素宽度越大,那么它缩小的比例也应该相应增大。所以在计算缩小的大小时,还要把元素宽度这个权重因素考虑进去。
如果不设置 flex-shrink
的属性值,那么所有元素默认为 1,意味着元素按照本身宽度的比例进行缩小,宽度越大的元素,当然缩小的也就越多。
几个常见的属性值
flex 的默认值为 0 1 auto,表明子元素最大不会超过自身的宽度(width),如果父元素宽度比子元素宽度之和小,则会进行等比缩小。
另外,flex 还有两个可识别的属性值,一个是 auto,一个是 none。
1 | flex: auto; |
等价于
1 | flex: 1 1 auto; |
如果子元素未设置宽度,且 flex 属性设置均为 auto,那么子元素将完全平分父元素宽度。
如果子元素设置了宽度,且 flex 属性设置均为 auto,则按照子元素的宽度比例进行缩放。
1 | flex: none; |
等价于
1 | flex: 0 0 auto; |
如果子元素未设置宽度,且 flex 属性设置均为 none,那么子元素宽度与内容宽度相同,内容越长,宽度越大。
如果子元素设置了宽度,且 flex 属性设置均为 none,则严格按照 width 属性进行显示。
一针见血的总结
flex 属性之所以很难理解,是因为 flex-grow
和 flex-shrink
之间存在着一个非常大的不同,flex-shrink
不仅依赖于属性值,还依赖于元素本身的大小,但 flex-grow
只与属性值有关。
Happy Ending。