到目前为止,Flexbox布局应该是目前最流行的布局方式之一了。而Flexbox布局的最大特性就是让Flex项目可伸缩,也就是让Flex项目的宽度和高度能够自动填充Flex容器剩余的空间或者缩小Flex项目适配Flex容器不足的宽度。而这一切都是依赖于Flexbox属性中的flex
属性来完成。一个Flex容器会等比的按照各Flex项目的扩展比率分配Flex容器剩余空间,也会按照收缩比率来缩小各Flex项目,以避免Flex项目溢出Flex容器。但其中Flex项目又是如何计算呢?他和扩展比率或收缩比率之间又存在什么关系呢?在这篇文章中咱们将一块儿来探来。css
在Flexbox布局中,容器中显示式使用
display
设置为flex
或inline-flex
,那么该容器就是Flex容器,而该容器的全部子元素就是Flex项目。css3
在这篇文章中,咱们将要聊的是有关于flex
属性的事情,特别是如何使用该属性来计算Flex项目?在开始以前,先来简单的了解一下flex
属性。浏览器
在Flexbox中,flex
属性是flex-grow
(扩展比率)、flex-shrink
(收缩比率)和flex-basis
(伸缩基准)三个属性的简称。这三个属性能够控制一个Flex项目(也有人称为Flex元素),主要表如今如下几个方面:wordpress
flex-grow
:Flex项目的扩展比率,让Flex项目获得(伸张)多少Flex容器多余的空间(Positive free space)flex-shrink
:Flex项目收缩比率,让Flex项目减去Flex容器不足的空间(Negative free space)flex-basis
:Flex项目未扩展或收缩以前,它的大小是多少在Flexbox布局中,只有充分理解了这三个属性才能完全的掌握Flex项目是如何扩展和收缩的,也才能更完全的掌握Flexbox布局。所以掌握这三个属性,以及他们之间的计算关系才是掌握Flexbox布局的关键所在。布局
在具体介绍flex
相关的技术以前,先对几个概念进行描述,由于理解了这几个概念更有易于你们对后面知识的理解。测试
Flex项目在主轴方向的宽度或高度就是Flex项目的主轴长度,Flex项目的主轴长度属性是width
或height
属性,具体是哪个属性,将会由主轴方向决定。flex
在Flexbox布局中,Flex容器中包含一个或多个Flex项目(该容器的子元素或子节点)。Flex容器和Flex项目都有其自身的尺寸大小,那么就会有:Flex项目尺寸大小之和大于或小于Flex容器 情景:spa
举个例子向你们阐述这两个情形:“假设咱们有一个容器(Flex容器),显式的给其设置了width
为800px
,padding
为10px
,而且box-sizing
设置为border-box
”。根据CSS的盒模型原理,咱们能够知道Flex容器的内宽度(Content盒子的宽度)为800px - 10px * 2 = 780px
:3d
假设Flex容器中包含了四个Flex项目,并且每一个Flex项目的width
都为100px
,那么全部Flex项目的宽度总和则是100px * 4 = 400px
(Flex项目没有设置其余任何有关于盒模型的尺寸),那么Flex容器将会有剩余的空间出来,即780px - 400px = 380px
。这个380px
就是咱们所说的Flex容器的剩余空间:code
假设把Flex项目的width
从100px
调到300px
,那么全部Flex项目的宽度总和就变成了300px * 4 = 1200px
。这个时候Flex项目就溢出了Flex容器,这个溢出的宽度,即1200px - 780px = 420px
。这个420px
就是咱们所说的Flex容器的不足空间:
上面演示的是主轴在
x
轴方向,若是主轴变成y
轴的方向,一样存在上述两种情形,只不过把width
变成了height
。接下来的内容中,若是没有特殊说明,那么所看到的示例都仅演示主轴在x
轴的方向,即flex-direction
为row
!
min-content
和max-content
是CSS中的一个新概念,隶属于CSS Intrinsic and Extrinsic Sizing Specification模块。简单的能够这么理解。
CSS能够给任何一个元素显式的经过width
属性指定元素内容区域的宽度,内容区域在元素padding
、border
和margin
里面。该属性也是CSS盒模型众多属性之一。
记住,CSS的
box-sizing
能够决定width
的计算方式。
若是咱们显式设置width
为关键词auto
时,元素的width
将会根据元素自身的内容来决定宽度。而其中的min-content
和max-content
也会根据元素的内容来决定宽度,只不过和auto
有较大的差别
min-content
: 元素固有的最小宽度max-content
: 元素固有的首选宽度好比下面这个示例:
若是内容是英文的话,min-content
的宽度将取决于内容中最长的单词宽度,中文就有点怪异(其中之因目前并未深究),而max-content
则会计算内容排整行的宽度,有点相似于加上了white-space:nowrap
同样。
上例仅展现了
min-content
和max-content
最基本的渲染效果(Chrome浏览器渲染行为)。这里不作深刻的探讨论,毕竟不是本文的重点,若是感兴趣,欢迎关注后续的相关更新,或者先阅读@张鑫旭 老师写的一篇文章《理解CSS3max/min-content
及fit-content
等width
值》
回到咱们本身的主题上来。
前面在介绍Flex剩余空间和不足空间的时候,咱们能够得知,出现这两种现象取决于Flex容器和Flex项目的尺寸大小。而flex
属性能够根据Flex容器的剩余空间(或不足空间)对Flex项目进行扩展(或收缩)。那么为了计算出有多少Flex容器的剩余空间能用于Flex项目上,客户端(浏览器)就必须知道Flex项目的尺寸大小。要是没有显式的设置元素的width
属性,那么问题就来了,浏览器它是如何解决没有应用于绝对单位的宽度(或高度)的Flex项目,即如何计算?
这里所说的min-content
和max-content
两个属性值对于咱们深刻的探讨flex
属性中的flex-grow
和 flex-grow
属性有必定的影响。因此提早向你们简单的阐述一正是这两个属性值在浏览器中的渲染行为。
简单的总结一下:
min-content
的大小,从本质上讲,是由字符串中最长的单词决定了大小;max-content
则和min-content
想反. 它会变得尽量大, 没有自动换行的机会。若是Flex容器太窄, 它就会溢出其自身的盒子!
在Flexbox布局当中,其中 flex-grow
、flex-shrink
和flex-basis
都将会影响Flex项目的计算。接下来咱们经过一些简单的示例来阐述这方面的知识。
flex-basis
属性在任何空间分配发生以前初始化Flex项目的尺寸。其默认值为auto
。若是flex-basis
的值设置为auto
,浏览器将先检查Flex项目的主尺寸是否设置了绝对值再计算出Flex项目的初始值。好比说,你给Flex项目设置的width
为200px
,那么200px
就是Flex项目的flex-basis
值。
若是你的Flex项目能够自动调整大小,则auto
会解析为其内容的大小,这个时候,min-content
和max-content
变会起做用。此时将会把Flex项目的max-content
做为 flex-basise
的值。好比,下面这样的一个简单示例:
flex-grow
和flex-shrink
的值都为0
,第一个Flex项目的width
为150px
,至关于flex-basis
的值为150px
,而另外两个Flex项目在没有设置宽度的状况之下,其宽度由内容的宽度来设置。
若是flex-basis
的值设置为关键词content
,会致使Flex项目根据其内容大小来设置Flex项目,叧怕是Flex项目显式的设置了width
的值。到目前为止,content
还未获得浏览器很好的支持。
flex-basis
除了能够设置auto
、content
、fill
、max-content
、min-content
和fit-content
关键词以外,还能够设置<length>
值。若是<length>
值是一个百分比值,那么Flex项目的大小将会根据Flex容器的width
进行计算。好比下面这个示例:
Flex容器显式设置了width
(和box-sizing
取值有关系,上图为border-box
的示例结果),那么flex-basis
会根据Flex容器的width
计算出来,若是Flex容器未显示设置width
值,则计算出来的结果将是未定义的(会自动根据Flex容器的宽度进行计算)。
在Flexbox布局中,若是你想彻底忽略Flex项目的尺寸,则能够将flex-basis
设置为0
。这样的设置,基本上是告诉了浏览器,Flex容器全部空间均可以按照相关的比例进行分配。
来看一个简单的示例,Flex项目未显式设置width
状况之下,flex-basis
不一样取值的渲染效果。
到写这篇文章为止,使用Firefox浏览器查看效果更佳。
当Flex项目显式的设置了min-width
或max-width
的值时,就算Flex项目显式的设置了flex-basis
的值,也会按min-width
和max-width
设置Flex项目宽度。当计算的值大于max-width
时,则按max-width
设置Flex项目宽度;当计算的值小于min-width
时,则按min-width
设置Flex项目宽度:
有关于flex-basis
属性相关的运用简单的小结一下:
flex-basis
默认值为auto
width
值,同时flex-basis
为auto
时,则Flex项目的宽度为按width
来计算,若是未显式设置width
,则按Flex项目的内容宽度来计算width
值,同时显式设置了flex-basis
的具体值,则Flex项目会忽略width
值,会按flex-basis
来计算Flex项目flex-basis
来计算,会根据flex-grow
和flex-shrink
设置的值给Flex项目分配相应的空间width
值,而是经过flex-basis
来控制Flex项目的宽度,这样更具弹性min-width
或max-width
值时,当flex-basis
计算出来的值小于min-width
则按min-width
值设置Flex项目宽度,反之,计算出来的值大于max-width
值时,则按max-width
的值设置Flex项目宽度前面提到过,flex-grow
是一个扩展因子(扩展比例)。其意思是,当Flex容器有必定的剩余空间时,flex-grow
可让Flex项目分配Flex容器剩余的空间,每一个Flex项目将根据flex-grow
因子扩展,从而让Flex项目布满整个Flex容器(有效利用Flex容器的剩余空间)。
flex-grow
的默认值是0
,其接受的值是一个数值,也能够是一个小数值,但不支持负值。一旦flex-grow
的值是一个大于0
的值时,Flex项目就会占用Flex容器的剩余空间。在使用flex-grow
时能够按下面的方式使用:
flex-grow
值flex-grow
值不一样的设置获得的效果将会不同,但flex-grow
的值始终总量为1
,即Flex项目占有的量之和(分子)和分母相同。咱们来具体看看flex-grow
对Flex项目的影响。
当全部的Flex项目具备一个相同的flex-grow
值时,那么Flex项目将会平均分配Flex容器剩余的空间。在这种状况之下将flex-grow
的值设置为1
。好比下面这个示例,Flex容器(width: 800px
,padding: 10px
)中有四个子元素(Flex项目),显式的设置了flex-basis
为150px
,根据前面介绍的内容,咱们能够知道每一个Flex项目的宽度是150px
,这样一来,全部Flex项目宽度总和为150px * 4 = 600px
。容器的剩余空间为780px - 600px = 180px
。当显式的给全部Flex项目设置了flex-grow
为1
(具备相同的值)。这样一来,其告诉浏览器,把Flex容器剩余的宽度(180px
)平均分红了四份,即:180px / 4 = 45px
。而flex-grow
的特性就是按比例把Flex容器剩余空间分配给Flex项目(固然要设置了该值的Flex项目),就该例而言,就是给每一个Flex项目添加了45px
,也就是说,此时Flex项目的宽度从150px
扩展到了195px
(150px + 45px = 195px
)。以下图所示:
特别声明,若是Flex项目均分Flex容器剩余的空间,只要给Flex项目设置相同的
flex-grow
值,大于1
便可。好比把flex-grow
设置为10
,就上例而言,把剩余空间分红了40
份,每一个Flex项目占10
份。其最终的效果和设置为1
是等效的。
上面咱们看到的均分Flex容器剩余空间,事实上咱们也能够给不一样的Flex项目设置不一样的flex-grow
值,这样一来就会让每一个Flex项目根据本身所占的比例来占用Flex容器剩余的空间。好比上面的示例,把Flex项目的flex-grow
分别设置为1:2:3:4
。也就是说把Flex容器的剩余空间分红了10
份(1 + 2 + 3 + 4 = 10
),而每一个Flex项目分别占用Flex容器剩余空间的1/10
、2/10
、3/10
和4/10
。就上例而言,Flex容器剩余空间是180px
,按这样的计算能够得知,每一份的长度是180px / 10 = 18px
,如此一来,每一个Flex项目的宽度则变成:
150px + 18px * 1 = 168px
150px + 18px * 2 = 186px
150px + 18px * 3 = 204px
150px + 18px * 4 = 222px
最终效果以下图所示:
前面两个示例向你们演示了,Flex项目均分和非均分Flex容器剩余的空间。从示例中能够看出来,flex-grow
的值都是大于或等于1
的数值。事实上,flex-grow
还能够设置小数。好比,给全部Flex项目设置flex-grow
的值为0.2
。因为Flex项目的flex-grow
的值都相等,因此扩展的值也是同样的,惟一不一样的是,全部的Flex项目并无把Flex容器剩余空间所有分完。就咱们这个示例而言,四个Flex项目的flex-grow
加起来的值是0.8
,小于1
。换句话说,四个Flex项目只分配了Flex容器剩余空度的80%
,按上例的数据来计算,便是180px * .8 = 144px
(只分去了144px
),并且每一个Flex项目分得都是36px
(144px / 4 = 36px
或者 144px * 0.2 / 0.8 = 36px
)。最终效果以下图所示:
上面的示例中,flex-basis
都显式的设置了值。事实上,flex-grow
和flex-basis
会相互影响的。这也令咱们的Flex项目计算变得复杂化了。好比说,flex-basis
的值为auto
,并且没有给Flex项目显式的设置width
。根据前面的内容咱们能够得知,此时Flex项目的大小都取决于其内容的max-content
大小。此时Flex容器的剩余的空间将由浏览器根据Flex项目的内容宽度来计算。好比接下来的这个示例,四个Flex项目都是由其内容max-content
大小决定。同时将flex-grow
都设置为1
(均匀分配Flex容器剩余空间)。具体的数据由下图所示(Chrome浏览器计算得出的值):
特别注意,不一样浏览器对小数位的计算略有差别,上图是在Chrome浏览器下得出的值。因此最终加起来的值略大于Flex容器的宽度
708px
。
针对这样的使用场景,若是你想让全部Flex项目具备相同的尺寸,那么能够显式的设置Flex项目的flex-basis
值为0
(flex: 1 1 0
)。从flex-basis
一节中能够得知,当flex-basis
值为0
时,表示全部空间均可以用来分配,并且flex-grow
具备相同的值,所以Flex项目能够获取均匀的空间。如此一来Flex项目宽度将会相同。
flex-basis
还能够由其余值为设置Flex项目的宽度,这里再也不一一演示。感兴趣的同窗能够本身根据flex-basis
的取值写测试用例。换句话说,若是你理解了前面介绍的flex-basis
内容,就能更好的理解flex-grow
和flex-basis
相结合对Flex项目分配Flex容器剩余空间的计算。也将不会再感到困惑。
flex-shrink
和flex-grow
相似,只不过flex-shrink
是用来控制Flex项目缩放因子。当全部Flex项目宽度之和大于Flex容器时,将会溢出容器(flex-wrap
为nowrap
时),flex-shrink
就能够根据Flex项目设置的数值比例来分配Flex容器的不足空间,也就是按比例因子缩小自身的宽度,以避免溢出Flex容器。
flex-shrink
接收一个<number>
值,其默认值为1
。也就是说,只要容器宽度不足够容纳全部Flex项目时,全部Flex项目默认都会收缩。若是你不想让Flex项目进行收缩时,能够设置其值为0
,此时Flex项目始终会保持原始的fit-content
宽度。一样的,flex-shrink
也不接受一个负值作为属性值。
基于上面的示例,简单的调整一下参数,全部Flex项目都设置了flex: 0 0 300px
,能够看到Flex项目溢出了Flex容器:
在这个示例中,因为flex-shrink
显式的设置了值为0
,Flex项目不会进行收缩。若是你想让Flex项目进行收缩,那么能够把flex-shrink
设置为1
。
从上图的结果咱们能够看出,当全部Flex项目的flex-shrink
都设置为相同的值,好比1
,将会均分Flex容器不足空间。好比此例,全部Flex项目的宽度总和是1200px
(flex-basis: 300px
),而Flex容器宽度是780px
(width: 800px
,padding: 10px
,盒模型是border-box
),能够算出Flex容器不足空间为420px
(1200 - 780 = 420px
),由于全部Flex项目的flex-shrink
为1
,其告诉浏览器,将Flex容器不足空间均分红四份,那么每份则是105px
(420 / 4 = 105px
),这个时候Flex项目就会自动缩放105px
,其宽度就由当初的300px
变成了195px
(300 - 105 = 195px
)。
这个示例演示的是Flex项目设置的值都是相同的值,其最终结果是将会均分Flex容器不足空间。其实flex-shrink
也能够像flex-grow
同样,为不一样的Flex项目设置不一样的比例因子。好比1:2:3:4
,这个时候Flex项目就不会均分了,而是按本身的比例进行收缩,比例因子越大,收缩的将越多。以下图所示:
就上图而言,全部Flex项目的flex-shrink
之和为10
(1 + 2 + 3 + 4 = 10
),此时把Flex容器不足空间420px
分红了十份,每一份42px
(420 / 10 = 42px
),每一个Flex项目按照本身的收缩因子相应的去收缩对应的宽度,此时每一个Flex项目的宽度就变成:
300 - 42 * 1 = 258px
300 - 42 * 2 = 216px
300 - 42 * 3 = 174px
300 - 42 * 4 = 132px
按照该原理来计算的话,当某个Flex项目的收缩因子设置较大时,就有可能会出现小于0
的现象。基于上例,若是把第四个Flex项目的flex-shrink
设置为15
。这样一来,四个Flex项目的收缩因子就变成:1:2:3:15
。也就是说把Flex容器不足空间分红了21
份,每份占据的宽度是20px
(420 / 21 = 20px
)。那么Flex项目的宽度就会出现0
的现象(300 - 15 * 20 = 0
)。这个时候会不会出现无空间容纳Flex项目的内容呢?事实上并不会这样:
在Flexbox布局当中,会阻止Flex项目元素宽度缩小至
0
。此时Flex项目会以min-content
的大小进行计算,这个大小是它们利用任何能够利用的自动断行机会后所变成的
若是某个Flex项目按照收缩因子计算得出宽度趋近于0
时,Flex项目将会按照该元素的min-content
的大小来设置宽度,同时这个宽度将会转嫁到其余的Flex项目,再按相应的收缩因子进行收缩。好比上例,Flex项目四,其flex-shrink
为15
,但其宽度最终是以min-content
来计算(在该例中,Chrome浏览器渲染的宽度大约是22.09px
)。而这个22.09px
最终按照1:2:3
的比例分配给了Flex项目一至三(Flex1,Flex2和Flex3)。对应的Flex项目宽度就变成:
300 - 20 * 1 - 22.09 / 6 * 1 = 276.334px
300 - 20 * 2 - 22.09 / 6 * 2 = 252.636px
300 - 20 * 3 - 22.09 / 6 * 3 = 228.955px
min-content
,在该例中大约是22.09px
对于该情形,计算相对而言就更为复杂一些了。但浏览器会很聪明的帮你处理这些场景,会倾向于给你合理的结果。只不过你们须要知道这样的一个细节,碰到相似的场景才不会一脸蒙逼(^_^)。
flex-grow
能够设置一个小于0
的值,一样的,flex-shrink
也能够设置一个小于0
的值,好比咱们给全部的Flex项目设置flex-shrink
的值为0.2
,你将看到的结果以下:
从结果的示例图中咱们能够看出来,当全部Flex项目的收缩因子(flex-shrink
)总和小于1
时,Flex容器不足空间不会彻底分配完,依旧会溢出Flex容器。比如该例,flex-shrink
的总和是.8
,分配了Flex容器剩余空间420px
的80%
,即336px
(还有84px
剩余空间未彻底分配完),因为每一个Flex项目的收缩因子是相同的,比如前面的示例,都设置了1
相似,把分配的空间336px
均分为四份,也就是84px
,所以每一个Flex项目的宽度由当初的300px
变成了216px
(300 - 84 = 216px
)。这个其实和flex-grow
相似,只不过flex-shrink
只是收缩而以。
Flex项目伸缩计算是一个较为复杂的过程,但它们之间仍是有据可查。@Chris和@Otree对该方面就有深刻的研究。他们给Flex项目的计算总结出了一套计算公式,具体公式以下:
@Chris还依据这套公式写了一个JavaScript的案例,来模拟Flex项目计算。
大部分情形之下,咱们都是使用flex
属性来设置Flex项目的伸缩的值。其常见值的效果有:
flex: 0 auto
和flex:initial
,这两个值与flex: 0 1 auto
相同,也是初始值。会根据width
属性决定Flex项目的尺寸。当Flex容器有剩余空间时,Flex项目没法扩展;当Flex容器有不足空间时,Flex项目收缩到其最小值min-content
。flex: auto
与flex: 1 1 auto
相同。Flex项目会根据width
来决定大小,可是彻底能够扩展Flex容器剩余的空间。若是全部Flex项目均为flex: auto
、flex:initial
或flex: none
,则Flex项目尺寸决定后,Flex容器剩余空间会被平均分给是flex:a uto
的Flex项目。flex: none
与flex: 0 0 auto
相同。Flex项目根据width
决定大小,可是彻底不可伸缩,其效果和initial
相似,这种状况下,即便在Flex容器空间不够而溢出的状况之下,Flex项目也不会收缩。flex: <positive-number>
(正数)与flex: 1 0px
相同。该值使Flex项目可伸缩,并将flex-basis
值设置为0
,致使Flex项目会根据设置的比例因子来计算Flex容器的剩余空间。若是全部Flex项目都使用该模式,则它们的尺寸会正比于指定的伸缩比。默认状态下,伸缩项目不会收缩至比其最小内容尺寸(最长的英文词或是固定尺寸元素的长度)更小。能够靠设置
min-width
属性来改变这个默认状态。
经过前面的内容介绍,应该能够了解到Flex项目的大小计算是很是的复杂。若是要真正的理解Flex项目是如何工做的话,最为关键的是理解有多少东西参与影响Flex项目。咱们能够按下面这样的方式来进行思考。
在CSS中设置一个元素的基本大小能够经过width
来设置,或者经过min-width
或max-width
来设置元素的最小或最大宽度,在将来咱们还能够经过content
、min-content
、max-content
或fit-content
等关键词来设置元素的大小。对于Flex项目,咱们还能够经过flex-basis
设置Flex项目大小。对于如何设置Flex项目的基本大小,咱们能够围绕如下几点来进行思考:
flex-basis
的值是auto
?Flex项目显式的设置了宽度吗?若是设置了,Flex项目的大小将会基于设置的宽度flex-basis
的值是auto
仍是content
?若是是auto
,Flex项目的大小为原始大小flex-basis
的值是0
的长度单位吗?若是是这样那这就是Flex项目的大小flex-basis
的值是0
呢? 若是是这样,则Flex项目的大小不在Flex容器空间分配计算的考虑以内更为具体的能够参阅flex-basis
相关的介绍。
若是Flex容器没有剩余空间,Flex项目就不会扩展;若是Flex容器没有不足空间,Flex项目就不会收缩:
flex-grow
会发挥做用, 具体如何发挥做用,能够参阅flex-grow
相关的介绍flex-shrink
会发挥做用,具体如何发挥做用,能够参阅flex-shrink
相关的介绍若是咱们不想把Flex容器的剩余空间扩展到Flex项目中,咱们可使用Flexbox中其余属性,好比justify-content
属性来分配剩余空间。固然也能够给Flex项目设置margin
值为处理Flex容器剩余空间。不过这一部分没有在这里阐述,若是感兴趣的话,不仿阅读一下Flexbox相关的介绍。
好久觉得,一直觉得Flexbox布局中,Flex项目都会根据Flex容器自动计算。而事实上呢?正如文章中介绍的同样,Flex项目的计算是至关的复杂。设置Flex项目大小的值以及flex-basis
、flex-grow
和flex-shrink
的设置都会对其有较大的影响,并且它们的组合场景也是很是的多,而且不一样的场景会形成不同的结果。
固然,文章中所介绍的内容或许没有覆盖到全部的场景,但这些基本的演示或许能帮助你们更好的理解Flex项目是如何计算的。最后但愿该文对你们有所帮助,若是你有更深的了解欢迎在下面的评论中与我一块儿分享。若是文章中有不对之处,还望各路大婶拍正。
原文连接本文为云栖社区原创内容,未经容许不得转载。