当前位置: 首页 > 科技观察

深入理解Flex布局和计算

时间:2023-03-16 23:16:57 科技观察

的原因对于Flex布局,看了大魔老师等老师写的文章,还是不太明白Flexbox是如何灵活计算子级item的大小的,一些其他详情。在大魔老师的帮助下,我去查了一下Flexbox的W3C规范文档。注意:这篇博文不适合没有接触过Flex布局的人,如果你想了解Flex布局的基础知识。请参考理解弹性盒:你需要知道的一切弹性盒模型的设计期望弹性盒模型被设计成:在任何流动方向(包括上、下、左、右)的良好布局可以在reverseorderorinanyorder排列布局可以沿主轴线性排列或沿侧轴缠绕。它可以在任何容器中灵活缩放(今天重点研究的主题),子元素可以排列在容器的主轴方向或容器的侧面。轴方向对齐可以沿主轴方向动态缩放child的尺寸,同时保证parent侧轴的尺寸。它们如何切换侧轴首先,每个轴包括三个东西:维度、方向和大小。这是什么意思?所谓维度,其实是指子元素水平或垂直排列(x轴或y轴)。方向是子元素的顺序或倒序。width[height]:每个子元素在主轴方向所占的面积positions之和如果主轴是水平的,那么size就是父元素中所有item的outerWidth之和。如果主轴是垂直的,那么大小就是父元素的outerHeight。主轴依赖于flex-direction和主轴方向的所有子元素。-size的和是确定的,flex-direction属性可以控制子元素的排列方向和顺序。横轴由flex-wrap和主轴方向所有子元素的item-size之和决定。flex-wrap可以控制子元素在横轴方向的排列顺序。下面我们会讨论不同类型和情况下的item-size,现在可以简单理解为width[height]。为了方便flex-direction+flex-wrap,将盗版规范中的一张图片组合成一个属性flex-flow。通过这个简单而复杂的属性,我们可以控制所有子元素的水平方向和垂直方向、倒序和顺序。有和没有换行符。主轴和副轴的切换非常简单。设置主轴时,默认设置其垂直面为侧轴。如:flex-flow:row-reversewrap-reverse;这个CSS属性能告诉我们什么信息?子元素横向排列,主轴为水平横轴,横轴为纵轴,子元素逆序沿主轴排列,子元素从右向左包裹。轴向排列,从下往上FFC(flexformattingcontext)Flexbox布局新定义了一个格式化上下文,类似于BFC(blockformattingcontext)。它有多相似?也就是说,除了布局和一些细节之外,所有规则都与BFC相同。注意:我所说的Flexbox是指带有display:flex;的盒子。或显示:inline-flex;放。它不仅仅指带有display:flex的盒子;放。例如,带有display:flex的元素;或者display:inline-flex和BFC一样,不会被浮动元素覆盖,垂直边距不会塌陷等等。对于设置了display:inline-flex的box,我们可以类比display:inline-box;来理解。也就是说,一个确定的Flexbox。不会占一行,但可以设置宽高。与BFC有细微差别,但需要注意以下几点。Flexbox布局和Block布局之间存在细微差别。Flexbox不支持::first-line和::first-letter这两个伪元素。Flexbox中的vertical-alignfloat和clear属性对Flexbox中的子元素没有影响,不会使子元素脱离文档流(但对Flexbox有影响!)多列布局(column-*)in在Flexbox中也是无效的,也就是说我们不能在Flexbox中使用多列布局来排列其下的子元素(鱼和熊掌不可兼得)。Flexbox下的子元素不会继承父容器(flex子元素)的widthflexitemCSS解析器会定义display:flex;和显示:inline-flex;Flexbox外面的子元素变成了一个不可见的盒子,我们通过排列这些盒子来达到排序、布局、拉伸的目的。规范称这种盒子为flexitem,子元素包括标签节点和文本节点。标签节点很容易理解,但文本节点需要注意。默认情况下,flex会将连续的文本节点打包成flex-item,这样文本就可以和label节点一起进行排序和定位。值得注意的是空格也是文本节点,所以white-space会影响Flexbox中的布局:setwhite-space:preFlexboxflex-item-size如何计算item-size(大小)就是item的内容在主轴方向加上自己的margin、border和padding就是这个item的大小。规范中介绍了flex-item内容的计算方式分为以下几种情况:1.flex-basis的优先级高于width[height]:non-auto;如果子元素没有内容且默认固定宽高,则设置Addedflex-basis。flex-item内容由flex-basis决定,不管width[height]设置多少。(可以理解为flex-basis的优先级高于width[height]:non-auto;)flex-basis的优先级高于width[height]。无论设置多少width[height],flex-item的内容都会以flex-basis来决定。2.元素有默认的宽度和高度。如果一个子元素有默认的固定宽高(比如input标签)并且设置了flex-basis,那么它的内容有一个固定的宽高作为下限。如果flex-basis超过固定的宽度和高度,则flex-basis成为它的内容。如果flex-basis小于固定宽高,则使用固定宽高作为内容。对于固定元素的尺寸设置3.元素有min-width[height]或max-width[height]如果flex-item有min-width[min-height]限制,则flex-item内容遵循min-widthvalue是下限。如果flex-basis的值大于min-width[min-height],那么flex-item的内容是根据flex-basis计算的。如果flex-basis的值小于min-width[min-height],则flex-item内容按min-width[min-height]计算:如果min-width[min-height]的值已经超过容器的大小,然后即使设置了flex-shrink。CSS解析器不会收缩这个item的内容,而是坚持保留它的min-width[min-height]:如果Flexbox设置的min-width超出了flex容器的范围,则不会压缩。反之,如果设置了max-width[height]的值,那么flex-basis不能超过这个值,flex-grow只会增长到max-width[height]的上限。在接下来的章节中,我们将详细讨论这种情况下布局的计算。4.宽度[高度]:自动;优先级等于flex-basis。前面说过,如果item同时设置了width[height]和flex-basis。flex-item内容由flex-basis决定。但实际上默认的width[height]:auto;优先级等于flex-basis。CSS解析器比较两者的值,取大者作为item的基本尺寸。如果一个item没有内容,flex-item的内容将由flex-basis决定。但是如果item有内容,并且内容的大小大于flex-basis,那么flex-item的内容将由width[height]:auto;决定;并且不能缩小。反之,如果小于flex-basis,flex-item内容将由flex-basis:width:auto决定;如果content长度大于flex-basis,那么flex-item内容将由content长度决定,如果flex-basis的长度大于text内容长度,则flex-item内容不能收缩,所以flex-item内容为由flex-basis和flex-basis决定:800px;和width:1px同时设置;flex-item内容由flex-basis决定,shrink注2我设置flex-shrink:1为1号框;我为1号和3号盒子设置了flex-shrink:0;意思是我把需要收缩的空间全部压到2号框,一共需要收缩的空间是0*600+1*20+0*100=-20;而2号框只有20个空格,应该是完全缩小到0了,但值得注意的是2号框并没有完全缩小,还是保留了一个字的距离。此外,溢出:隐藏;也会影响溢出:隐藏;并将文本长度限制为600px;小于flex-basis:700px;所以flex-item内容由flex-basis决定,可以收缩。隐藏属性对项目大小的影响我测试了项目的属性,例如显示:无;可见性:隐藏;能见度:崩溃;变换:缩放;等等。结果如下:如果flex-itemcontentwithvisibility:hidden;|负自由空间分配给他们。如果显示:没有设置;CSS解析器不会计算项目的空间,也不会增长空间。关于position:absolute影响项目position:absolute也适用于Flexbox中的子元素,设置了position:absolute属性的子元素也会受到Flexbox排列的影响。设置为absolute的子元素重叠在一起,但仍然会受到align-items:center;的影响居中。对于Flexbox,设置position:absolute;不会对其下的子元素产生任何影响。下面重点看看Flexbox下的子元素设置为absolute后的结果。根据我做的实验,得到如下结论:flexbox下子元素设置为absolute的位置受三个方面的影响:flexbox流下的justify-content和align-items单个子元素的Top、left、rightelement,bottom单个子元素的margin这里我们不讨论translate因为translate只是视觉位置的变化:设置absolute的item不会影响布局,如图,其中12345是有absolute设置的item,6、7、8、9th是没有absolute设置的itemFlexbox。我设置了justify-content:center;并对齐项目:居中;我给每个itemmargin:20px;:可以看出,由于绝对原因,12345号item不会影响6789号的排列。结论:item脱离文档流不会影响正常的flex布局。如上第4项所示,设置了absolute但未设置top/left值,位置居中下。结论:如果位置:绝对;在子元素上设置属性而不设置topleft的这些值。子元素受Flexbox的justify-content:center、align-items:center和margin影响。如图,第1235项,我分别给他们设置了top、left、right、bottom等值。5号元素设置margin-left:50px;和底部填充:-999999px;结论:top、left、right、bottom等值会覆盖justify-content:center;并对齐项目:居中;item自由定位。margin会影响item从头到尾的位置,而padding不会(我试过设置padding为500px,padding会影响item的大小)。如果为parent的justify-content和align-items设置了非center的值:如果设置了flex-start,则所有元素不分离,定位在主轴起点;如果设置了flex-start,则所有元素不分离,位于主轴的末端;如果设置了justify-content:space-around;效果等同于center,即所有元素堆叠在一起居中,item不会产生区间;如果你设置justify-content:space-between;效果等同于flex-start,并且item不会分开;如果设置了align-items:flex-start;所有元素都没有分开,位于横轴的起点;如果align-items:flex-end已设置;所有元素都没有分开,位于交叉轴的末端;如果对齐项目:拉伸|基线;如果设置了align-self,则没有任何效果,项目将不会跟随侧轴拉伸或根据基线对齐,除了flex-start|弹性端|center有效此外,其他无效。通过上面一系列的测试,我们可以清楚的了解到justify-content、align-items和top、left、right、bottom都是position属性,top、left、right、bottom会覆盖justify-content和value对齐项目。(以上前提是必须设置position:absolute,否则top、left、right、bottom都无效)。margin的优先级与top、left、right、bottom的优先级相同,也就是说margin设置的值和top、left、right、bottom会同时生效。优先顺序是:margin=justify-content|对齐项目>顶部、左侧、右侧、底部。flex-basis,flex-grow,flex-shrink以及对应的计算内联柔性;会不会生效,并且只对axis方向生效。如果主轴是水平的,即flex-direction:row;然后flex-basis、flex-grow、flex-shrink控制单个item的宽度。如果主轴是竖直的,即flex-direction:column;然后flex-basis、flex-grow、flex-shrink控制单个item的高度。而flex-grow和flex-shrink用于在主轴方向上拉伸(负)可用空间。有两种情况,换行或不换行。1.如果是flex-wrap:nowrap;意味着没有换行符。然后所有item会在主轴方向排成一行,css解析器会计算item在主轴方向占用的空间,对比计算flexbox在主轴方向占用的空间主轴。如果item占用的空间比Flexbox小,说明Flexbox还没有被填满,CSS解析器会计算还有多少空间还没有填满,并根据flex-grow设置的值来分配这些空间每个项目按比例分配给每个项目。可用空间如果item占用的空间比Flexbox大,说明Flexbox满了,CSS解析器会计算超出多少空间,根据每个item设置的flex-shrink值来分配这些空间按比例缩小每一项超出的空间那么CSS解析器在这种情况下是如何计算的呢?我们在上一章中努力理解的项目大小终于派上用场了。flex-grow的计算过程是:availablespace=flexbox-content-eachitem-size的总和,将每个item的所有grow设置相加,可用空间除以grow,得到单位分配空间。根据每个item的growth集合计算,如果一个item的growth为2,那么这个item在主轴上的大小需要扩展2*单位分配空间的大小。那么每个item都需要在原来的基础上加上分配的size来完成grow:分配前分配后的简单理解就是多余的部分,可能多也可能少,按照growth分配到x份。为每个项目设置的份数除以每个项目之间的差异。注意:flex-shrink和flex-grow的计算过程不同。flex-shrink的计算过程是:首先将所有item按照flex-shrink*item-size相加得到加权和,然后计算每个item的收缩比例:shrinkratio=flex-shrink*item-size/的之前的金额;然后计算子元素超出父元素的部分(负自由空间),每一项减去收缩率*负自由空间:收缩前和收缩后2。如果是flex-wrap:wrap[wrap-reverse];即如果换行,item会先在主轴方向排列成多行,CSS解析器会先计算主轴方向每行的大小,并与Flexbox容器的宽度[高度]。互不干扰:在分配前均匀分布后,如果一行累计的item-size超过了Flexbox的大小,则会安排另一行进行排列,所以这种情况下不会发生shrink,但只增长案例。在max-width[height]的情况下,flex-grow的计算过程中可能会有一项或多项设置了max-width[height]。因此,CSS引擎会先进行分配。分配后,它会计算那些具有max-width[height]的项目。]的item重分配过程min-width[height]在flex-shrink计算过程中,由于可能有一个或多个item,所以设置了min-width[height]。所以CSS引擎会先进行一次shrink,shrink之后统计那些有min-width[height]的item,shrink之后是否还有剩余未收缩的空间,然后将剩余的空间分配给没有设置的最小宽度[高度]项目。注意:第一次收缩的算法和第二次分配未收缩的剩余空间的算法不同!总结Flexbox布局很棒。它为我们省去了很多适配的工作,但还是需要一点门槛才能理解和使用好。再次感谢@大沙师的大力帮助,谢谢。