标签:影响 play 用例 模块 包含 提前 需要 min 16px
到目前为止,Flexbox布局应该是目前最流行的布局方式之一了。而Flexbox布局的最大特性就是让Flex项目可伸缩,也就是让Flex项目的宽度和高度可以自动填充Flex容器剩余的空间或者缩小Flex项目适配Flex容器不足的宽度。而这一切都是依赖于Flexbox属性中的flex
属性来完成。一个Flex容器会等比的按照各Flex项目的扩展比率分配Flex容器剩余空间,也会按照收缩比率来缩小各Flex项目,以免Flex项目溢出Flex容器。但其中Flex项目又是如何计算呢?他和扩展比率或收缩比率之间又存在什么关系呢?在这篇文章中我们将一起来探来。
在Flexbox布局中,容器中显示式使用
display
设置为flex
或inline-flex
,那么该容器就是Flex容器,而该容器的所有子元素就是Flex项目。
在这篇文章中,我们将要聊的是有关于flex
属性的事情,特别是如何使用该属性来计算Flex项目?在开始之前,先来简单的了解一下flex
属性。
在Flexbox中,flex
属性是flex-grow
(扩展比率)、flex-shrink
(收缩比率)和flex-basis
(伸缩基准)三个属性的简称。这三个属性可以控制一个Flex项目(也有人称为Flex元素),主要表现在以下几个方面:
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
属性,具体是哪一个属性,将会由主轴方向决定。
在Flexbox布局中,Flex容器中包含一个或多个Flex项目(该容器的子元素或子节点)。Flex容器和Flex项目都有其自身的尺寸大小,那么就会有:Flex项目尺寸大小之和大于或小于Flex容器 情景:
举个例子向大家阐述这两个情形:“假设我们有一个容器(Flex容器),显式的给其设置了width
为800px
,padding
为10px
,并且box-sizing
设置为border-box
”。根据CSS的盒模型原理,我们可以知道Flex容器的内宽度(Content盒子的宽度)为800px - 10px * 2 = 780px
:
假设Flex容器中包含了四个Flex项目,而且每个Flex项目的width
都为100px
,那么所有Flex项目的宽度总和则是100px * 4 = 400px
(Flex项目没有设置其他任何有关于盒模型的尺寸),那么Flex容器将会有剩余的空间出来,即780px - 400px = 380px
。这个380px
就是我们所说的Flex容器的剩余空间:
假设把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项目是如何计算的。最后希望该文对大家有所帮助,如果你有更深的了解欢迎在下面的评论中与我一起分享。如果文章中有不对之处,还望各路大婶拍正。
原文链接
本文为云栖社区原创内容,未经允许不得转载。
标签:影响 play 用例 模块 包含 提前 需要 min 16px
原文地址:https://www.cnblogs.com/yunqishequ/p/10006872.html