从一个简单的例子开始
flex
布局本意是提供良一种弹性良好的布局方式,根据这个思路就可以理解它为什么设计这些API
。它是这样一种叙事语言:指定了容器的方向,是否允许换行,排列方向,子元素在两个方向上的排布倾向,以及轴线的排布倾向后,就可以形成一个良好的弹性布局。
同时,因为子元素可能有自己的想法,所以也需要给它们特定的API:它们可以自己决定顺序,副轴的对齐方式,还有如何占据剩余空间。我们会发现,子元素无法定义自己再主轴上的对齐方式,这可能是因为一旦设置就不好处理。
这样一想,flex
布局不是万能的——虽然配合 margin
等属性,它可以几乎是完备的。
那么,首先聊一聊 flex
布局如何决定元素的宽度。先从一个例子开始:
<div class="fc"> <div id="a"></div> <div id="b"></div> <div id="c"></div> <div id="d"></div> </div> <style> .fc { border: 2px black solid; height: 100px; width: 300px; display: flex; } #a { background-color: red } #b { background-color: blue } #c { background-color: green } #d { background-color: yellow } .fc > div { height: 100px } /** 实验代码写在这里 **/ .fc > div { width: 100px; } <style>
一个flex容器元素里装着4个正方形。这种情况下,会不会溢出呢?
答案是否定的:
每个元素都收窄以适应父元素的宽度。现在每个子元素的宽度都是75px
。看上去width
属性好像失效了,可是事实真是这样吗?想象一下每个子元素的宽度是怎么计算出来的:
- 计算所有子元素的总宽度,这里是
400
- 计算剩余空间,得
300-400 = -100
- 由于剩余空间为负数,寻找
flex-shrink
属性 flex-shrink
相同,每个元素收缩相同的值100/4=25
,得75
从这里我们可以看出flex-shrink
属性的默认值为1
。 如果我们改成0
的话:
它超出了。
现在让我们去掉两个子元素,这样父元素的宽度就超过子元素了。
子元素没有拉伸。这意味着,子元素的 flex-grow
属性默认值是0
。如果我们不加 width
,那么会子元素的宽度会变成0
.
现在,我们人为给它加上 1:3
的 flex-grow
,结果如下:
- 计算所有子元素的总宽度,这里是
200
- 计算剩余空间,得
300-200 = -100
- 由于剩余空间为正数,寻找
flex-grow
属性 flex-grow
为1:3
,剩余空间据此分配,得a
的宽度为100+100*1/4=125
现在我们可以得出结论:flex
布局中首先根据子元素的基准值计算剩余空间,再根据属性分配剩余空间,得出最后的宽度。
而 width
,则是决定基准值的一个影响因素。 flex-basis
可以直接指定基准值。
flex-basis 与 width
flex-basis
指定了元素的基准值。它的默认值是 auto
,代表 元素本身的大小。
元素本身的大小又是什么呢?这时候我们就要看向 width
。准确来说是:min-width || max-width -> width -> Content Size
如果flex-basis
设定了具体的值,那么优先级要高于width
这是否是说,其它条件不变的前提下,flex-basis
等同于 width
了呢?
看上去好像没什么区别?其实不适的。这里的不同确实非常微妙。我们不卖关子,直接给出结论:
如果我们指定了 width
,通常情况下元素的宽度就是给定值(这里要结合box-sizing
)。但是, flex-basis
并不代表元素的宽度。当内容必须超出的时候,元素的宽度可能超过给定的基准值。
现在,我们加上 white-space
,不允许换行。
注意到区别了吗?
总结:当flex-basis
的content-box
无法再缩小时,flex-basis
允许宽度变大,也就是说不会溢出;而width
则不会改变宽度,这必然导致content-box
溢出。
flex:1
发生了什么?
flex 三个属性分别对应:flex-grow
, flex-shrink
, flex-basis
,也就是伸缩基
这样的顺序。
那么,根据各个属性的默认值我们知道flex
的默认值是:0 1 auto
flex
属性有一个常用值是 flex: 1
。这是否是flex1 1 auto
的简写呢?
答案是否定的。
实际上规范明确指出了此时代表了什么:
flex: <positive-number> Equivalent to flex: <positive-number> 1 0. Makes the flex item flexible and sets the flex basis to zero, resulting in an item that receives the specified proportion of the free space in the flex container. If all items in the flex container use this pattern, their sizes will be proportional to the specified flex factor.
换句话说,flex:1
等于 flex:1 1 0
那么,这两者有区别吗?
当然是有的。
根据上一节的描述,如果不给width
, flex-basis:auto
的元素的基准宽度由content-box
决定。而flex-basis:0
,则基准宽度为0。这代表了什么?剩余宽度不同!
换句话说,如果子元素有内容,flex: 1 1 auto
是无法三等分的。
结语
好了,看一下这篇文章说了什么。
- 首先,我们知道
flex
布局中,子元素的宽度根据剩余宽度和子元素的基准值得出。 - 其次,我们知道子元素的基准值和
width
有关。 - 接着,
width
不能完全取代flex-basis
,两者的行为在很小的范围内会不同,因为flex-basis
会保证内容不溢出。 - 然后,我们查证
flex:1
等于flex:1 1 0
,而不适flex: 1 1 auto
- 最后,根据
1-3
,我们知道flex: 1 1 0
会完全三等分,flex: 1 1 auto
内容则会造成影响。
flex 的坑真的很多。如果想要更详细的了解,推荐张天旭老师的文章: Oh My God,CSS flex-basis原来有这么多细节
我也会不断记录自己遇到的问题。