flex布局的几个进阶面试题

456 阅读3分钟

image

flex布局的几个进阶面试题

  1. flex属性默认值是多少,flex:1代表什么?
    flex属性默认值:flex: 0 1 auto ​

    flex: 1​​​代表

    flex-grow: 1;
    flex-shrink: 0;
    flex-basis: auto;
    
  2. flex伸缩的计算公式
    答:

    以第i个flex子项的flex属性设置为 flex: FgiFsiFbiF{gi}\,\,F_{si}\,\,F_{bi}

    伸展因子算法:

    Ffi=Fgi1nFgiF_{fi} = \frac{F_{gi}}{\sum_{1}^{n}F_{gi}}

    压缩因子算法:

    Ffi=FsiFbi1nFsiFbiF_{fi} = \frac{F_{si}*F_{bi}}{\sum_{1}^{n}{F_{si}*F_{bi}}}

    flex子项在主轴方向上的尺寸FSfiFS_{fi},其中GSGS为伸缩空间

    GS=Sfc1nFbiFSfi=Fbi+/GSFfiGS = S_{fc}-{\sum_{1}^n F_{bi}} \\ \\ FS_{fi} = F_{bi} +/- GS*F_{fi}

    当然这是在flex子项本身在主轴方向没有其他尺寸限制属性的情况下的计算。如果存在其他限制,则采用先预计算;如果符合限制,则和没有限制一样,采用预计算方案直接布局;如果不符合限制,将有限制的子项元素按照限制layout以后,再由其他flex子项元素按照上述公式进行计算得出尺寸。

    举一些例子

    1. 伸展

      <div class="flex-container container-1">
      	<div class="flex-item item-1"></div>
      	<div class="flex-item item-2"></div>
      	<div class="flex-item item-3"></div>
      </div>
      
      .flex-container {
      	height: 200px;
      	width: 500px;
      	margin: 100px auto;
      	border: 1px solid #5b5252;
      
      	display: flex;
      }
      
      .flex-item {
      	height: 100%;
      }
      
      .container-1 > .item-1 {
      	flex: 1 3 100px;
      }
      
      .container-1 > .item-2 {
      	flex: 6 1 200px;
      }
      
      .container-1 > .item-3 {
      	flex: 3 6 100px;
      }
      

      最终布局:

      image

      flex子项总宽度:100+200+100=400<500100+200+100=400<500,所以flex子项伸展,伸缩空间: 500400=100px500-400=100px

      item-1​​宽度: 100px+11+6+3100px=110px100px+\frac{1}{1+6+3}*100px = 110px

      item-2​​宽度:200px+61+6+3100px=260px200px+\frac{6}{1+6+3}*100px = 260px

      item-3​​宽度:100px+31+6+3100px=130px100px+\frac{3}{1+6+3}*100px=130px

    2. 压缩

      <div class="flex-container container-2">
      	<div class="flex-item item-1"></div>
      	<div class="flex-item item-2"></div>
      	<div class="flex-item item-3"></div>
      </div>
      
      .flex-container {
      	height: 200px;
      	width: 500px;
      	margin: 100px auto;
      	border: 1px solid #5b5252;
      
      	display: flex;
      }
      
      .flex-item {
      	height: 100%;
      }
      
      .container-2 > .item-1 {
      	flex: 1 3 100px;
      }
      
      .container-2 > .item-2 {
      	flex: 6 1 200px;
      }
      
      .container-2 > .item-3 {
      	flex: 3 6 300px;
      }
      
      

      最终布局:

      ​​image​​

      flex子项总宽度:100+200+300=600>500100+200+300=600>500,所以flex子项需要压缩,伸缩空间: 600500=100px600-500=100px

      item-1​​宽度: 100px31003100+1200+6300100px=86.96px100px-\frac{3*100}{3*100+1*200+6*300}*100px = 86.96px

      item-2​​宽度:200px12003100+1200+6300100px=191.30px200px-\frac{1*200}{3*100+1*200+6*300}*100px = 191.30px

      item-3​​宽度:300px63003100+1200+6300100px=221.74px300px-\frac{6*300}{3*100+1*200+6*300}*100px=221.74px

    3. 伸展+max-width限制

      <div class="flex-container container-3">
      	<div class="flex-item item-1"></div>
      	<div class="flex-item item-2"></div>
      	<div class="flex-item item-3"></div>
      </div>
      
      .flex-container {
      	height: 200px;
      	width: 500px;
      	margin: 100px auto;
      	border: 1px solid #5b5252;
      
      	display: flex;
      }
      
      .flex-item {
      	height: 100%;
      }
      
      .container-3 > .item-1 {
      	flex: 1 3 100px;
      }
      
      .container-3 > .item-2 {
      	flex: 6 1 200px;
      }
      
      .container-3 > .item-3 {
      	flex: 3 6 100px;
      	max-width: 120px;
      }
      

      最终布局:

      image

      预计算:

      flex子项总宽度:100+200+100=400<500100+200+100=400<500,所以flex子项伸展,伸缩空间: 500400=100px500-400=100px

      item-1​​宽度: 100px+11+6+3100px=110px100px+\frac{1}{1+6+3}*100px = 110px

      item-2​​宽度:200px+61+6+3100px=260px200px+\frac{6}{1+6+3}*100px = 260px

      item-3​​宽度:100px+31+6+3100px=130px100px+\frac{3}{1+6+3}*100px=130px

      item-3​​预计算宽度130px,超过max-width:120px​​限制,为item-3​​设置满足限制的尺寸,排除item-3​​进行重新计算

      flex子项总宽度:100+200=300<500120=380100+200=300<500-120=380,所以flex子项伸展,伸缩空间:380300=80px380-300 = 80px

      item-1​​宽度:100px+11+680px=111.42px100px+\frac{1}{1+6}*80px = 111.42px

      item-2​​宽度:200px+61+680px=268.58px200px+\frac{6}{1+6}*80px = 268.58px

      item-3​​宽度:120px120px

    4. 压缩+min-width限制

      <div class="flex-container container-4">
      	<div class="flex-item item-1"></div>
      	<div class="flex-item item-2"></div>
      	<div class="flex-item item-3"></div>
      </div>
      
      .flex-container {
      	height: 200px;
      	width: 500px;
      	margin: 100px auto;
      	border: 1px solid #5b5252;
      
      	display: flex;
      }
      
      .flex-item {
      	height: 100%;
      }
      
      .container-4 > .item-1 {
      	flex: 1 3 100px;
      }
      
      .container-4 > .item-2 {
      	flex: 6 1 200px;
      }
      
      .container-4 > .item-3 {
      	flex: 3 6 300px;
      	min-width: 280px;
      }
      

      预计算:

      flex子项总宽度:100+200+300=600>500100+200+300=600>500,所以flex子项压缩,伸缩空间: 600500=100px600-500=100px

      item-1​宽度: ​100px31003100+1200+6300100px=86.96px100px-\frac{3*100}{3*100+1*200+6*300}*100px = 86.96px

      item-2​宽度:200px12003100+1200+6300100px=191.30px200px-\frac{1*200}{3*100+1*200+6*300}*100px = 191.30px

      item-3​宽度:300px63003100+1200+6300100px=221.74px300px-\frac{6*300}{3*100+1*200+6*300}*100px=221.74px

      item-3​预计算宽度221。74px,不满足min-width:280px​限制,为item-3​设置满足限制的尺寸,排除item-3​进行重新计算

      flex子项总宽度:100+200=300>500280=220100+200=300>500-280=220,所以flex子项伸展,伸缩空间:300220=80px300-220 = 80px

      item-1​宽度:100px31003100+120080px=52px100px-\frac{3*100}{3*100+1*200}*80px = 52px

      item-2​宽度:200px31003100+120080px=168px200px-\frac{3*100}{3*100+1*200}*80px= 168px

      item-3​宽度:280px280px
      image

    5. flex: 1​的正常伸展情况

      <div class="flex-container container-5">
      	<div class="flex-item item-1"></div>
      	<div class="flex-item item-2"></div>
      </div>
      
      .flex-container {
      	height: 200px;
      	width: 500px;
      	margin: 100px auto;
      	border: 1px solid #5b5252;
      
      	display: flex;
      }
      
      .flex-item {
      	height: 100%;
      }
      
      .container-5 > .item-1 {
      	flex: 0 0 100px;
      }
      
      .container-5 > .item-2 {
      	flex: 1;
      }
      

      item-1​ 宽度:100px

      item-2​ 伸展,宽度:500100=400px500-100=400px

    6. flex: 1​的溢出情况

      <div class="flex-container container-6">
      	<div class="flex-item item-1">
      		<span class="item-text">我撑开父元素的宽度</span>
      	</div>
      	<div class="flex-item item-2">
      		<span class="item-text">我也撑开父元素的宽度,我也撑开父元素的宽度,我也撑开父元素的宽度</span>
      	</div>
      </div>
      
      .flex-container {
      	height: 200px;
      	width: 500px;
      	margin: 100px auto;
      	border: 1px solid #5b5252;
      
      	display: flex;
      }
      
      .flex-item {
      	height: 100%;
      }
      
      .container-6 > .item-1 {
      	flex: 0 0 100px;
      }
      
      .container-6 > .item-1 > .item-text {
      	white-space: nowrap;
      }
      
      .container-6 > .item-2 {
      	flex: 1;
      }
      
      .container-6 > .item-2 > .item-text {
      	white-space: nowrap;
      }
      

      ​​image​​

      观察到item-1​和item-2​的宽度都存在异常。

      1. 即使item-1​的flex-grow​指定为0​,其宽度仍然超过flex: 0 0 100px​中的100px
      2. 即使item-2​的flex-shrink​指定为0​,其宽度仍然导致溢出。

      原因请看第三个问题的答案。

  3. flex布局为什么会出现flex子项设置了<span style="font-weight: bold;" data-type="strong">flex-grow: 0</span>尺寸仍然超过<span style="font-weight: bold;" data-type="strong">flex-basis</span>设置,flex子项开启了压缩(<span style="font-weight: bold;" data-type="strong">flex-shrink</span>不为0)仍然产生溢出的现象?
    min-width/min-height​ 这两个属性在一般情况下默认值都是0,也就是说没有限制最小尺寸。但是flexbox规范中明确规定,当container开启flex布局以后,flex子项的min-width/min-height​属性默认值会被修改为auto。

    auto的含义:

    当flex子项还具有子元素时,flex子项在主轴方向的默认最小限制是该子项的子元素尺寸该子项本身的<span style="font-weight: bold;" data-type="strong">width/height</span>​​​的较小值

    所以flex: 0 0 300px​ 的元素不一定在主轴方向是300px​,flex: 0 1 auto​的元素在主轴方向上不一定不溢出。

  4. flex布局中flex-basis​​​, width/height​​​,以及主轴尺寸关系
    flex-basis​​​定义flex子项在主轴方向上伸缩的基础尺寸。
    width/height​​​在flex-basis​​​为auto时,设定flex-basis​​​的同时,设置flex子项的默认最小宽度限制

    主轴尺寸:当flex容器没有设定主轴尺寸时,主轴尺寸由各个flex子项的主轴尺寸决定。

  5. 主轴方向为column的flex布局,很多时候没有开启的必要,请不要随手开启。