css flex布局 准确计算成员宽度值

栏目: CSS · 发布时间: 5年前

内容简介:css 的 flex 弹性布局,广泛应用在当今的页面开发中,其弹性伸缩的的灵活性非常擅长于开发有响应式需求的网站。但是有很多时候,其灵活性也会让人疑惑,特别是确定尺寸时,基本上是靠不断尝试。为了在开发时更加得心应手,下面将以主轴方向上,也就是默认布局方向上的成员宽度值计算为例子进行研究。flex 是弹性的伸缩布局,具有伸和缩两个特性,下面在研究时也以伸和缩两种状态来进行研究。 在开始之前,先说一下一些定义,类名 container 是 flex 容器, 类名 item 是 flex 的成员对象,每个成员对象

前言

css 的 flex 弹性布局,广泛应用在当今的页面开发中,其弹性伸缩的的灵活性非常擅长于开发有响应式需求的网站。但是有很多时候,其灵活性也会让人疑惑,特别是确定尺寸时,基本上是靠不断尝试。为了在开发时更加得心应手,下面将以主轴方向上,也就是默认布局方向上的成员宽度值计算为例子进行研究。

准备

flex 是弹性的伸缩布局,具有伸和缩两个特性,下面在研究时也以伸和缩两种状态来进行研究。 在开始之前,先说一下一些定义,类名 container 是 flex 容器, 类名 item 是 flex 的成员对象,每个成员对象内嵌了自已的内容。每个成员都设置了相应的外边距、边框、内边距,为了方便表述把每个成员的外边距宽度的左右宽度和表述为 margin,类似的表述为 border、padding,在下面的计算中会有提及。最后把每个成员的内容区域宽度表述为 content。在下面的例子中我们会发现,成员的最终宽度大小是由成员的 width flex-basic 和 content 值共同决定,在不同状态下也会分别受到 flex-grow 和 flex-shrink 的影响

下面的 flex 布局中设置了 6 个成员,每个成员都设置了不同的 width flex-basic content flex-grow 值

<div class="wrapper">
  <h1>test</h1>
  <style>
    .container { display: flex; background-color: #915151;}
    .item { height: 80px; text-align: center; background-color: rgb(214, 120, 52);border-radius: 1em; border: 5px solid #000;text-align: left;margin: 15px; padding: 10px }  
</style>
  <div class="container">
    <div class="item" style="flex-grow: 1;width: 100px; flex-basis: 0">     
      <div style="width: 40px"></div>
    </div>
    <div class="item" style="flex-grow: 0; width: 250px; flex-basis: 200px">      
        <div style="width: 300px"></div>    
    </div>
    <div class="item" style="flex-grow: 2; flex-basis: 200px">      
        <div></div>    
    </div>
    <div class="item" style="flex-grow: 2;  width: 70px">      
        <div></div>    
    </div>
    <div class="item" style="flex-grow: 2;">      
        <div style="font-family: monospace;">12345678910111213141516</div>    
    </div>
    <div class="item" style="flex-grow: 3; width: 200px;">      
        <div style="width: 100px"></div>    
    </div>
  </div>
</div>复制代码

下面是生成布局的截图,包括了每个成员的尺寸

css flex布局 准确计算成员宽度值

css flex布局 准确计算成员宽度值 css flex布局 准确计算成员宽度值 css flex布局 准确计算成员宽度值 css flex布局 准确计算成员宽度值

css flex布局 准确计算成员宽度值 css flex布局 准确计算成员宽度值

最内层的区域就是成员的大小区域,也就是成员的宽度和高度值,从宽度值可以看出,有的元素的宽度值和成员的 content 大小一样, 有的和成员的 width 值一样,有的和两者都不同,下面将通过公式来计算各个成员的最终宽度值。

由于不是每个成员都设置了相应的 flex-basis、width 和 内容的 width 值,所以我先定下下面的规则来补充缺失的参数值,设置 t-flex-basis 为转化的 flex-basis 值, t-width 为转化的 width 值,t-content 为转化的 content 值

  1. 成员的 flex-basis 值存在, 那么 t-flex-basis 值就是该值,如果不存在,那么 t-flex-basis 值就是 t-width 的值
  2. 成员的 width 值存在, 那么 t-width 的值就是该值,如果不存在,,那么 t-width 值就是 t-content 的值
  3. 成员的 content 设置了 width 值, 那么 t-content 的值就是该值,如果不存在, 那么 t-content 值就是内部的首选最小尺寸值,像成员 3, 4 内部没有字符,那么其 t-content 就是 0,而成员 5 有一串不断行的字符,我故意把字体设置为等宽字体,在我的浏览器中每个字符是 6.5px,这里有 23 个字符,所以 t-content 就为 149.5px

通过以上规则,就可以把成员的参数值转化为下表的数据

css flex布局 准确计算成员宽度值

下面可以开始计算最终宽度值

计算步骤

  1. 获取剩余空间
  2. 分配剩余空间
  3. 找出不符合分配的成员,重新计算分配空间

获取剩余空间

剩余空间 = 容器可分配空间 -  每个成员(margin + border + padding + t-flex-basis)的和

在我这里的容器宽度是 1349px,这个也是这里的容器可分配空间

剩余空间 = 1349 - (30 + 10 + 20 + 0) - (30 + 10 + 20 + 200) - (30 + 10 + 20 + 200) - (30 + 10 + 20+ 70) - (30 + 10 + 20 + 149.5) - (30 + 10 + 20 + 200)  = 169.5

分配剩余空间

分配的剩余空间 = 剩余空间 * (当前成员的 flex-grow) / 待分配成员的 flex-grow 值之和

item1 分配的剩余空间  = 169.5 * 1 / (1 + 0 + 2 + 2 + 2 + 3) = 16.95

item2 分配的剩余空间 = 169.5 * 0 / (1 + 0 + 2 + 2 + 2 + 3) = 0

item3 分配的剩余空间 = 169.5 * 2 / (1 + 0 + 2 + 2 + 2 + 3) = 33.9

item4 分配的剩余空间 = 169.5 * 2 / (1 + 0 + 2 + 2 + 2 + 3) = 33.9

item5 分配的剩余空间 = 169.5 * 2 / (1 + 0 + 2 + 2 + 2 + 3) = 33.9

item6 分配的剩余空间 = 169.5 * 3 / (1 + 0 + 2 + 2 + 2 + 3) = 50.85

找出不符合分配的成员,重新计算分配空间

所谓不符合分配的成员指的是 (分配的剩余空间 + t-flex-basis) < min(t-content, t-width)

当成员不符合分配时,那么该成员的最终值就是 t-content 和 t-width 中的最小值

否则成员的最终值就是:分配的剩余空间 + t-flex-basis 

通过比较可以得到 item1 不符合分配

item1 (0 + 16.95) < min(t-content,t-width) = 40

所以 item1 的最终宽度是 40

由于 item1 如果是按分配应该是 16.95,现在是 40,多占据了 23.05

所以要重新分配空间,分配的空间中要减少相应比例的空间

item2 重新分配后的剩余空间 = 0 - 23.05 * 0 / (0 + 2 + 2 + 2 + 3) = 0

item3 重新分配后的剩余空间 = 33.9 - 23.05 * 2 / (0 + 2 + 2 + 2 + 3) = 28.78

item4 重新分配后的剩余空间 = 33.9 - 23.05 * 2 / (0 + 2 + 2 + 2 + 3) = 28.78

item5 重新分配后的剩余空间 = 33.9 - 23.05 * 2 / (0 + 2 + 2 + 2 + 3) = 28.78

item6 重新分配后的剩余空间 = 50.85 - 23.05 * 3 / (0 + 2 + 2 + 2 + 3) = 43.17

通过比较可以得到 item2 不符合分配

item2 (0 + 200) < min(250, 300) = 250

所以 item2 的最终宽度是 250

由于 item2 如果是按分配应该是 200,现在是 250,多占据了 50

所以要重新分配空间,分配的空间中要减少相应比例的空间

item3 重新分配后的剩余空间 = 28.78 - 50 * 2 / (2 + 2 + 2 + 3) = 17.67

item4 重新分配后的剩余空间 = 28.78- 50 * 2 / (2 + 2 + 2 + 3) = 17.67

item5 重新分配后的剩余空间 = 28.78- 50 * 2 / (2 + 2 + 2 + 3) = 17.67

item6 重新分配后的剩余空间 = 43.17 - 50 * 3 / (2 + 2 + 2 + 3) = 26.5

通过比较可以得到以上的成员都符号分配

item3 的最终宽度是 17.67 + 200 = 217.67

item4 的最终宽度是 17.67 + 70= 87.67

item5 的最终宽度是 17.67 + 149.5= 167.17

item6 的最终宽度是 26.5 + 200 = 226.5

可以看到计算结果和最终的结果是一致的

以上是关于在伸长状态下成员的计算规则,那么在收缩状态下,上面的计算公式还能起作用吗

下面的 flex 布局中设置了 6 个成员,每个成员都设置了不同的 width flex-basic content flex-shrink 值, 为了让元素处于收缩状态,我修改了成员的大小

<div class="wrapper">  
    <h1>test</h1>  
    <style>    
        .container {display: flex; background-color: #915151;}
        .item {height: 80px; text-align: center; background-color: rgb(214, 120, 52); border-radius: 1em;border: 5px solid #000;text-align: left;margin: 15px;padding: 10px}  
    </style>  
    <div class="container">    
        <div class="item" style="flex-shrink: 1;width: 100px; flex-basis: 500px">      
            <div style="width: 40px"></div>    
        </div>   
        <div class="item" style="flex-shrink: 0; width: 250px; flex-basis: 300px">      
            <div style="width: 300px"></div>    
        </div>    
        <div class="item" style="flex-shrink: 2; flex-basis: 500px">      
            <div></div>    
        </div>    
        <div class="item" style="flex-shrink: 2;  width: 400px">      
            <div></div>    
        </div>    
        <div class="item" style="flex-shrink: 2;">      
            <div style="font-family: monospace;">12345678910111213141516</div>    
        </div>    
        <div class="item" style="flex-shrink: 3; width: 300px;">      
            <div style="width: 100px"></div>    
        </div>  
      </div>  
</div>复制代码

下面是生成布局的截图,包括了每个成员的尺寸

css flex布局 准确计算成员宽度值 css flex布局 准确计算成员宽度值 css flex布局 准确计算成员宽度值 css flex布局 准确计算成员宽度值 css flex布局 准确计算成员宽度值 css flex布局 准确计算成员宽度值 css flex布局 准确计算成员宽度值

下面将通过公式计算成员最终的宽度值

按照前面提及的转化规则,得到类似下面的表格

css flex布局 准确计算成员宽度值

依据上面提到的计算步骤进行计算

获取剩余空间

剩余空间 = 容器可分配空间 - 每个成员(margin + border + padding + t-flex-basis)的和

在我这里的容器宽度是 1349px,这个也是这里的容器可分配空间

剩余空间 = 1349 - (30 + 10 + 20 + 500) - (30 + 10 + 20 + 300) - (30 + 10 + 20 + 500) - (30 + 10 + 20+ 400) - (30 + 10 + 20 + 149.5) - (30 + 10 + 20 + 300) = -1160.5

分配剩余空间

分配的剩余空间 = 剩余空间 * (当前成员的 flex-shrink) / 待分配成员的 flex-shrink值之和

item1 分配的剩余空间 = -1160.5 * 1 / (1 + 0 + 2 + 2 + 2 + 3) = -116.05

item2 分配的剩余空间 = -1160.5 * 0 / (1 + 0 + 2 + 2 + 2 + 3) = 0

item3 分配的剩余空间 = -1160.5 * 2 / (1 + 0 + 2 + 2 + 2 + 3) = -232.1

item4 分配的剩余空间 = -1160.5 * 2 / (1 + 0 + 2 + 2 + 2 + 3) = -232.1

item5 分配的剩余空间 = -1160.5 * 2 / (1 + 0 + 2 + 2 + 2 + 3) = -232.1

item6 分配的剩余空间 = -1160.5 * 3 / (1 + 0 + 2 + 2 + 2 + 3) = -348.15

找出不符合分配的成员,重新计算分配空间

所谓不符合分配的成员指的是 (分配的剩余空间 + t-flex-basis) < min(t-content, t-width)

当成员不符合分配时,那么该成员的最终值就是 t-content 和 t-width 中的最小值

否则成员的最终值就是:分配的剩余空间 + t-flex-basis

通过比较可以得到 item5 不符合分配

item5 (-232.1 + 149.5) < min(t-content,t-width) = 149.5

所以 item5 的最终宽度是 149.5

由于 item5 如果是按分配应该是 -82.6,现在是 149.5,多占据了 232.1

所以要重新分配空间,分配的空间中要减少相应比例的空间

item1 重新分配后的剩余空间 = -116.05 - 232.1 * 1 / (1 + 0 + 2 + 2 + 3) = -145.0625

item2 重新分配后的剩余空间 = 0 - 232.1 * 0 / (1 + 0 + 2 + 2 + 3) = 0

item3 重新分配后的剩余空间 = -232.1 - 232.1 * 2 / (1 + 0 + 2 + 2 + 3) = -290.125

item4 重新分配后的剩余空间 = -232.1 - 232.1 * 2 / (1 + 0 + 2 + 2 + 3) = -290.125

item6 重新分配后的剩余空间 = -348.15 - 232.1 * 3 / (1 + 0 + 2 + 2 + 3) = -435.1875

通过比较可以得到 item6 不符合分配

item6 (-435.1875 + 300) < min(300, 100) = 100

所以 item6 的最终宽度是 100

由于 item6 如果是按分配应该是 -135.1875,现在是 100,多占据了 235.1875

所以要重新分配空间,分配的空间中要减少相应比例的空间

item1 重新分配后的剩余空间 = -145.0625 - 235.1875 * 1 / (1 + 0 + 2 + 2) = -192.1

item2 重新分配后的剩余空间 = 0 - 235.1875 * 0 / (1 + 0 + 2 + 2) = 0

item3 重新分配后的剩余空间 = -290.125- 235.1875 * 2 / (1 + 0 + 2 + 2) = -384.2

item4 重新分配后的剩余空间 = -435.1875 - 235.1875 * 2 / (1 + 0 + 2 + 2) = -529.2625

通过比较可以得到 item4 不符合分配

item4 (-529.2625 + 400) < min(t-content,t-width) = 0

所以 item4 的最终宽度是 0

但是可以看到 item4 实际的渲染结果不是 0,所以以上的计算公式在收缩状态下是无效的,问题出现在计算剩余空间的计算上,在收缩状态下的计算公式是

分配的剩余空间 = 剩余空间 * (当前成员的 flex-shrink * t-flex-basis) / 待分配成员的(flex-shrink * t-flex-basis)之和

css flex布局 准确计算成员宽度值

重新计算以上的步骤

分配剩余空间

分配的剩余空间 = 剩余空间 * (当前成员的 flex-shrink * t-flex-basis) / 待分配成员的(flex-shrink * t-flex-basis)之和

item1 分配的剩余空间 = -1160.5 * 1 * 500 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400 + 2 * 149.5 + 3 * 300) = -165.83

item2 分配的剩余空间 = -1160.5 * 0 * 300 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400 + 2 * 149.5 + 3 * 300) = 0

item3 分配的剩余空间 = -1160.5 * 2 * 500 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400 + 2 * 149.5 + 3 * 300) = -331.666

item4 分配的剩余空间 = -1160.5 * 2 * 400 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400 + 2 * 149.5 + 3 * 300) = -265.33

item5 分配的剩余空间 = -1160.5 * 2 * 149.5 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400 + 2 * 149.5 + 3 * 300) = -99.168

item6 分配的剩余空间 = -1160.5 * 3 * 300 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400 + 2 * 149.5 + 3 * 300) = -298.5

找出不符合分配的成员,重新计算分配空间

所谓不符合分配的成员指的是 (分配的剩余空间 + t-flex-basis) < min(t-content, t-width)

当成员不符合分配时,那么该成员的最终值就是 t-content 和 t-width 中的最小值

否则成员的最终值就是:分配的剩余空间 + t-flex-basis

通过比较可以得到 item5 不符合分配

item5 (-99.168 + 149.5) < min(t-content,t-width) = 149.5

所以 item5 的最终宽度是 149.5

由于 item5 如果是按分配应该是 50.33,现在是 149.5,多占据了 99.17

所以要重新分配空间,分配的空间中要减少相应比例的空间

item1 分配的剩余空间 = -165.83 - 99.17 * 1 * 500 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400 + 3 * 300) = -181.325

item2 分配的剩余空间 = 0 - 99.17 * 0 * 300 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400 + 3 * 300) = 0

item3 分配的剩余空间 = -331.666 - 99.17* 2 * 500 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400  + 3 * 300) = -362.65

item4 分配的剩余空间 = -265.33 - 99.17 * 2 * 400 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400  + 3 * 300) = -290.1225

item6 分配的剩余空间 = -298.5 - 99.17 * 3 * 300 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400 + 3 * 300) = -326.39

通过比较可以得到 item6 不符合分配

item6 (-326.39 + 300) < min(300, 100) = 100

所以 item6 的最终宽度是 100

由于 item6 如果是按分配应该是 -26.39,现在是 100,多占据了 126.39

所以要重新分配空间,分配的空间中要减少相应比例的空间

item1 分配的剩余空间 = -181.325 - 126.39 * 1 * 500 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400) = -208.8

item2 分配的剩余空间 = 0 - 126.39 * 0 * 300 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400) = 0

item3 分配的剩余空间 = -362.65 - 126.39* 2 * 500 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400) = -417.6

item4 分配的剩余空间 = -290.1225 - 126.39 * 2 * 400 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400) = -334.08

通过比较可以得到以上成员都符号要求

item1 的最终宽度是 500 - 208.8 = 291.2

item2 的最终宽度是 0 + 300= 300

item3 的最终宽度是 -417.6 + 500= 82.4

item4 的最终宽度是 -334.08 + 400 = 65.9

可以看到计算结果和最终的结果是一致的

总结

从以上的分析和计算中,可以看到成员的宽度受多个参数所控制,主要属性是 flex-basis, 其中在伸长和收缩状态中,计算分配的剩余空间的公式是不同的,而且在计算中还会受到成员内容大小和成员自身大小的影响,成员的最终值不得小于成员内容大小和成员自身大小中的最小值,否则就取这个最小值并重新分配剩余空间。这里可以举一个例子,很多时候我们设置 flex: 1 并希望成员都是等分的,一般情况下是没有问题的。其中 flex: 1 实际上是 flex-basis: 0%, flex-grow: 1, flex-shrink: 1,如果你不能控制成员的内容大小,当这个内容尺寸大于等分尺寸时,由于没有设置 width 值, width 值默认等于内容大小,按照以上的分析,该尺寸就会改变成员宽度,造成等分的效果失效,要避免这种情况,可以设置 width 的值为 0,这样成员内容大小和成员自身大小中的最小值就为0,等分尺寸肯定大于该值,成员尺寸便取等分尺寸,当然这个时候成员内容就会溢出。

通过以上的分析,我们对计算成员宽度已经有初步的了解,基本上能应对大部分的情况,但是 flex 布局还不止以上的属性,而且不同的属性之间还能互相组合,甚至在有的时候可能在容器上设置了绝对定位(flex功能不会消失),或者成员上设置了 box-sizing(设置的 width 值可能不同于读取的 width 值),或者 width 值是百分比(父元素宽度不确定时,width 的表现像 auto,等父元素确定后才开始计算),flex-grow 或者 flex-shrink 是小数(满足特定情况计算规则会改变)等,在以上这些情况下计算时要考虑因素会更多。

为了研究 flex 布局规则,我特意写了一个测试页面,大家有兴趣也可以去看一下

flex 布局测试 changk99.github.io/flexbox/

css flex布局 准确计算成员宽度值


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

深度探索C++对象模型

深度探索C++对象模型

斯坦利•B.李普曼 (Stanley B. Lippman) / 侯捷 / 电子工业出版社 / 2012-1 / 69.00元

作者Lippman参与设计了全世界第一套C++编译程序cfront,这本书就是一位伟大的C++编译程序设计者向你阐述他如何处理各种explicit(明确出现于C++程序代码中)和implicit(隐藏于程序代码背后)的C++语意。 本书专注于C++面向对象程序设计的底层机制,包括结构式语意、临时性对象的生成、封装、继承,以及虚拟——虚拟函数和虚拟继承。这本书让你知道:一旦你能够了解底层实现模......一起来看看 《深度探索C++对象模型》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

SHA 加密
SHA 加密

SHA 加密工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试