css 的 flex 弹性布局在日常开发中有着广泛的应用,其弹性伸缩的灵活性对响应式需求的开发提供了便利,栅格布局,垂直居中等等设置flex布局后,加上几个属性就可以轻松实现。基本使用可以参考阮老师的博客

flex布局的特点

flex可以看成一个容器,其中有一个主轴(main axis)和交叉轴(cross axis)作为容器内容的排布基准。容器中的每个子元素称为项目,这些项目都排列在主轴(main axis)上,每个项目在主轴方向上占用空间称为main size。我们可以通过设置项目的width属性来指定main size的大小,也可以通过flex属性(flex-grow,flex-strink,flex-basic的结合)使main size大小成为响应式。

如何计算项目的大小

指定width属性

每个项目上直接设置width大小,项目大小即为width的值,这种方式不会让宽度自适应,如果容器宽度大于或小于项目宽度总和,就会出现容器有大量留白或超出容器的情况,为了避免这种情况,通常会指定flex属性来使项目宽度自适应从而占满整个容器。

项目总宽度小于容器宽度

指定flex-grow属性,项目会自动扩张到和容器宽度一致

项目宽度都设为auto

计算相加每个项目flex-grow得出总和为T,并将容器宽度W均分成W/T,每个项目的宽度就是

main size = flex-grow * W / T

演示地址

项目宽度设有width或flex-basic属性

容器宽度先减去这些项目width或flex-basic的值,容器剩下的宽度会按flex-grow来计算并分配给所有项目。main size = flex-basic + (W - 每个项目宽度) * flex-grow / T

*注:flex-basic的优先级高于width

演示地址

项目宽度设有max-width

项目宽度先按上面两个算法计算出宽度,如果项目宽度大于了max-width,多余的宽度会重新分配给没有设置max-width属性的项目。

演示地址

项目总宽度大于容器宽度

计算法则

指定flex-strink属性,项目宽度会自动收缩到和容器宽度一致。引用MND上的说法:

CSSflex-shrink​ 属性指定了 flex 元素的收缩规则。flex 元素仅在默认宽度之和大于容器的时候才会发生收缩,其收缩的大小是依据 flex-shrink 的值

其实这里收缩和扩张的算法是不一样的,收缩的大小不能直接用flex-strink来计算,以这段代码为例

.flex-item1 {
  background-color: red;
  flex: 0 8 800px;
}

.flex-item2 {
  background-color: gray;
  flex: 0 4 400px;
}

.flex-item3 {
  background-color: antiquewhite;
  flex: 0 2 200px;
}

.flex-item4 {
  background-color: orange;
  flex: 0 1 100px;
}

这里可以计算出项目的总宽度是 1500px 大于了容器宽度 1000px,按照MDN的说法,计算第一个项目的宽度应该是:800 - (1500 - 1000)*(8 / 15)= 533.33px

可以看出项目的收缩大小并不是通过flex-strink直接得到的,要计算项目的收缩后的宽度,还需要用到flex-basic。以上面的代码为例,先要去计算项目的虚拟总宽度VS = 各项目flex-basic flex-strink 之和,再计算单个项目的占比P = flex flex-strink / VS,最后计算项目应该减去的大小 = 真实超出部分 * P,

可以计算出第一个项目的宽度为:

项目中设有max-widh或min-width

先计算出项目收缩后的宽度,如果项目宽度大于了max-width,最终项目的大小会以max-width的值为准,且多余的宽度会分配给其他项目;如果项目小于了min-width,最终项目的大小会以min-width为准,且少分配的宽度会从其他项目中减去。分配给其他项目的这部分宽度要准守上面所写的计算规则按占比分配

演示地址

项目中既有max-width又有min-width

先计算出项目收缩后的宽度,按照“多退少补”的方式来处理max-width和min-width的情况,举个例子:

.flex-item1 {
  background-color: red;
  flex: 0 4 400px;
  /* 240 */
  min-width: 310px;
}

.flex-item2 {
  background-color: gray;
  flex: 0 2 400px;
  /* 320 */
  max-width: 280px;
}

.flex-item3 {
  background-color: antiquewhite;
  flex: 0 4 200px;
  /* 120 */
  max-width: 100px;
}

.flex-item4 {
  background-color: orange;
  flex: 0 2 200px;
  /* 160 */
}

.flex-item5 {
  background-color: lightcoral;
  flex: 0 2 200px;
  /* 160 */
}

项目1收缩后的宽度是240px,min-width是300px,所以项目1就借走了60px需要从其他项目中补上60px;项目2收缩后的宽度是320px,max-width是280px,所以项目2少了40px就退给其他项目;项目3页同理,120-100=20px,要退给其他项目20px。来来回回发现,就这项目1借的宽度刚好可以由项目2和项目3补上,互补之后两清了,于是,项目4和项目5的宽度不受影响不变化。

演示地址

其他影响宽度计算的例子

容器上设有flex-wrap=wrap属性

项目的宽度超出了容器的宽度,超出部分的项目自动移动到到下一行去,在每一行中,项目的宽度计算都以flex-grow为准

演示地址

项目中设有position

如果position的值使项目脱离文档流,容器中的项目flex属性就会失效,其他的项目宽度按flex属性自适应。

演示地址

总结

flex布局中项目的自适应宽度(高度)通过flex-grow和flex-strink决定的,二者都是将容器中剩余或超出的宽度(高度)分配给各个项目,flex-grow是将剩余宽度按flex-grow比分配给各个项目,flex-strink是根据各个项目原本宽度*flex-strink占总虚拟宽度的比来分配项目应该减去的宽度。


Ezio
35 声望2 粉丝