Ashun's 技術駅 Ashun's 技術駅
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • HTML
  • CSS
  • Vue
  • 现代web布局
  • React
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 技术资源
  • 第一阶段

    • HTML
  • 第二阶段

    • JavaScript
  • 第三阶段

    • Vue
  • 第四阶段

    • 实战项目
  • 每周测试

    • 每周
  • 其他

    • Vue引入UI框架
    • Web前端面试
    • Vue3-resource
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 福利资源
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Ashun

前端界的小学生
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • HTML
  • CSS
  • Vue
  • 现代web布局
  • React
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 技术资源
  • 第一阶段

    • HTML
  • 第二阶段

    • JavaScript
  • 第三阶段

    • Vue
  • 第四阶段

    • 实战项目
  • 每周测试

    • 每周
  • 其他

    • Vue引入UI框架
    • Web前端面试
    • Vue3-resource
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 福利资源
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • HTML

  • CSS

  • Vue

  • 现代web布局

    • 01Web 布局技术演进:了解 Web 布局发展史
    • 02现代 Web 布局技术术语
    • 03Flexbox 布局基础使用
    • 04Flexbox 布局中的对齐方式
    • 05Flexbox 布局中的 flex 属性的基础运用
    • 06Flexbox 中的计算:通过扩展因子比例来扩展 Flex 项目
      • flex-grow 的计算
      • 小结
    • 07Flexbox 中的计算:通过收缩因子比例收缩 Flex 项目
    • 08Flexbox 布局中的 flex-basis:谁能决定 Flex 项目的大小?
    • 09使用 Flexbox 构建经典布局:10 种经典 Web 布局
    • 10Grid 布局的基础知识
    • 11定义一个网格布局
    • 12Grid 布局中的计算
    • 13可用于 Grid 布局中的函数
    • 14网格项目的放置和层叠
    • 15Grid 布局中的对齐方式
    • 16网格布局中的子网格和嵌套网格
    • 17使用子网格构建 Web 布局
    • 18使用 Grid 构建经典布局:10 种经典布局
    • 19使用 Grid 构建创意性 Web 布局
    • 20Flexbox or Grid:如何选择合适的布局?
    • 21display:contents 改变 Flexbox 和 Grid 布局模式
    • 22Web 中的向左向右:Flexbox 和 Grid 布局中的 LTR 与 RTL
    • 23Web 中的向左向右:Web 布局中 LTR 切换到 RTL 常见错误
    • 24内在 Web 设计
    • 25创建不规则 Web 布局
    • 26如何构建响应式 UI?
    • 27下一代响应式 Web 设计:组件式驱动式 Web 设计
    • 28下一代响应式 Web 设计:容器查询
  • React

  • 页面
  • 现代web布局
xugaoyi
2023-06-01
目录

06Flexbox 中的计算:通过扩展因子比例来扩展 Flex 项目

#

通过前面的课程学习(05 | Flexbox 布局中的 flex 基础运用 (opens new window) ),你可能已经知道了,在 Flex 项目上使用 flex 属性时,浏览器会根据具体的值来计算 Flex 项目,比如扩展 Flex 项目,或收缩 Flex 项目,或不变。我想大家一定很好奇它们是如何计算的。

接下来几节课,我们分别来看看 flex-grow 、flex-shrink 和 flex-basis 三个属性是如何对 Flex 项目产生影响的。

为了能帮助大家更好地理解 flex-grow 、flex-shrink 和 flex-basis 的计算,我们通过下面这个简单的示例着手:

<div class="container">
  <!-- Flex 项目 A -->
  <div class="item"><span>A</span>longlonglongword</div> 
  <!-- Flex 项目 B -->
  <div class="item"><span>B</span>ook</div>
  <!-- Flex 项目 C -->
  <div class="item"><span>C</span>ountries in the east</div>
  <!-- Flex 项目 D -->
  <div class="item"><span>D</span>iscuss</div>
  <!-- Flex 项目 E -->
  <div class="item"><span>E</span>astern</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
.container {
  display: flex;
  inline-size: 1000px;
  font-size: 1.5rem;
}

.item span {
  font-size: 3rem;
}
1
2
3
4
5
6
7
8
9

示例中有一个 Flex 容器 .container ,它的宽度是 1000px (设置了 inline-size),并且这个 Flex 容器包含了 五个 Flex 项目 ,我们分别以字母开头来对其命名,即 A 、B 、C 、 D 和 E 。

在代码中没有给任何 Flex 项目显式设置尺寸(width 、inline-size 或 flex-basis 等),所以它们的尺寸分别是由每个 Flex 项目所在内容的最大宽度(max-content)来决定的,不过它们会受文本相关属性值的影响,比如 font-size 、font-family (字形的宽度或高度 (opens new window))、特定单词和文本的长度(比如长字符单词)、Flex 项目包含元素固有或指定的大小(比如示例中的span 元素):

  • Flex 容器可用空间是 1000px ;
  • Flex 项目 A 的宽度约是 237.56px;
  • Flex 项目 B 的宽度约是 70.26px;
  • Flex 项目 C 的宽度约是 243.30px;
  • Flex 项目 D 的宽度约是 100.69px ;
  • Flex 项目 E 的宽度约是 100.11px ;
  • Flex 容器的剩余空间约是 248.08px 。

img

在此基础上,所有 Flex 项目的 flex-basis 都是初始值,即 auto ,width (或 inline-size)也是初始值 auto 。

注意,接下来的示例都以 flex-direction 为 row 展开,即只围绕着 Flex 项目的宽度计算为例!

# flex-grow 的计算

先来看 flex-grow 的计算。

首先,我们在所有 Flex 项目上显式设置 flex 的值为 1 :

.item {
    flex: 1;
}
1
2
3

通过课程前面的内容我们可以得知,flex:1 相当于:

.item {
  flex-grow: 1;
  flex-shrink: 1;
  flex-basis: 0%;
}
1
2
3
4
5

由于所有 Flex 项目的内容宽度总和(751.92px)小于 Flex 容器宽度(1000px)。结果,浏览器使用 flex-grow 的值作为 Flex 项目的扩展因子,每个 Flex 项目按扩展因子的比率瓜分了 Flex 容器的剩余空间(248.08px)。 此示例中的每个 Flex 项目都有一个 flex-grow 值为 1 和一个 flex-basis 值为 0 。

在此基础上,浏览器会按下面这个公式循环遍历每一个 Flex 项目以确定其灵活性(flexibility ):

img

注意,这里所说的灵活性(Flexibility)指运用于 Flex 项目的一个弹性值,有可能是加上这个弹性值,也有可能是减去这个弹性值。即可增加或减少的一个弹性量 。

这个“Flex 项目的灵活性(弹性量)” 并不是 Flex 项目的具体宽度,需要在该计算出来的值基础上,加上 Flex 项目的 flex-basis (或 width 或 inline-size)才是 Flex 项目的最终宽度值:

img

浏览器会根据该公式循环遍历计算 Flex 项目的灵活性(弹性量)。先根据公式来计算 Flex 项目 A 的灵活性。

Flex 项目 A的灵活性 = (Flex 容器的剩余空间  ÷ 所有 Flex 项目扩展因子 flex-grow 值总和 × 当前 Flex 项目自身的扩展因子 flex-grow

Flex 项目 A 的灵活性 = (1000px ÷ 5) × 1 = 200px
1
2
3

需要注意的是,当 Flex 项目未显式设置 flex-basis 、 width 或 inline-size 属性值时,浏览器将以 Flex 项目的内容长度(max-content)视为 Flex 项目的基础尺寸,但 Flex 容器的剩余空间等于 Flex 容器的可用空间 。

Flex 项目 A 具有 200px 的灵活性(弹性量)。接下来,将此灵活性值添加到 Flex 项目 A 的 flex-basis 值上,它的值是 0 ,即:

Flex 项目 A 计算后的宽度(flex-basis) = 0 + 200px = 200px
1

按理说,根据计算 Flex 项目 A 的 flex-basis 值应该是 200px ,即它的宽度是 200px ,但由于其内容是一个长单词("Alonglonglongword"),该词的最大内容长度大约是 237.56px 。浏览器没有将 Flex 项目 A 的大小设置为 200px ,而是将其宽度限制为 237.56px 的最小内容大小。

只有计算完 Flex 项目 A 之后,浏览器才会开始来计算 Flex 项目 B。减去 Flex 项目 A 计算出来的宽度值之后,Flex 容器的可用空间大约还有 762.44px ,分布在 Flex 项目 B、C、D 和 E 中。

按计算 Flex 项目 A 的方式来计算 Flex 项目 B 宽度:

Flex 项目 B 的灵活性 = (Flex 容器的剩余空间  ÷ 所有 Flex 项目扩展因子 flex-grow 值总和 × 当前 Flex 项目自身的扩展因子 flex-grow

Flex 项目 B 的灵活性 = (762.44px ÷ 4) × 1 = 190.61px

Flex 项目 B 计算后的宽度(flex-basis) = 0 + 190.61px = 190.61px
1
2
3
4
5

按同样的方式,可以计算出 Flex 项目 C 、 Flex 项目 D 和 Flex 项目 E 的宽度:

Flex 项目 C 计算后的宽度 = ((1000px - 237.56px - 190.61px) ÷ 3 ) × 1 + 0 = 190.61px

Flex 项目 D 计算后的宽度 = ((1000px - 237.56px - 190.61px - 190.61px) ÷ 2 ) × 1 + 0 = 190.61px

Flex 项目 E 计算后的宽度 =  ((1000px - 237.56px - 190.61px - 190.61px - 190.61px) ÷ 1 ) × 1 + 0 = 190.61px
1
2
3
4
5

img

如果你使用的是 Firefox 浏览器,使用开发者调试工具,可以很清楚看到每个 Flex 项目的计算前后的几个重要参数,比如内容宽度 flex-basis (未显式设置都是 0)、每个 Flex 项目的弹性量(Flexibility)和每个 Flex 项目计算后的宽度:

img

你可能认为,你已经知道 Flex 项目如何根据 flex-grow 来扩展 Flex 项目的尺寸(width 或 inline-size)了。如果你这么认为,那就太小看 Flex 项目计算了。上面仅仅是其中一种情况,即 flex-grow:1 和 flex-basis: 0% 且未在 Flex 项目上显式设置任何与尺寸有关的属性(比如 width 或 inline-size )。

如果我们把前面示例中的 flex:1 更换成 flex: 1 160px :

.item {
    flex: 1 160px;
    
    /* 等同于 */
    flex-grow: 1;
    flex-shrink: 1;
    flex-basis: 160px;
}
1
2
3
4
5
6
7
8

尝试着按照前面的计算公式来进行计算,需要注意的是,前面示例中我们未显式设置 flex-basis 的值,浏览器会视其为 0% ,此时浏览器将 Flex 容器的剩余空间计算为 1000px 。但我们这个示例中,显式设置了 flex-basis 的值为 160px ,那么对应的 Flex 容器的剩余空间就是 200px (即 (1000px - 160px × 5) = 200px )。

同样先计算 Flex 项目 A :

Flex 项目 A 的灵活性 = (Flex 容器的剩余空间  ÷ 所有 Flex 项目扩展因子 flex-grow 值总和 × 当前 Flex 项目自身的扩展因子 flex-grow

Flex 项目 A 的灵活性 = (200px ÷ 5) × 1 = 40px

Flex 项目 A 计算后的宽度(flex-basis) = 160px + 40px = 200px
1
2
3
4
5

同样的,因为 Flex 项目 A 的内容是一个长单词,它最终会以其内容的最小尺寸为准(即 min-content),大约是 237.56px 。接着浏览器将按同样的方式循环遍历每个 Flex 项目:

Flex 项目 B 计算后的宽度 = ((1000px - 237.56px) - 160px × 4) ÷ 4 × 1 + 160px = 190.61px

Flex 项目 C 计算后的宽度 = ((1000px - 237.56px - 190.61px) - 160px × 3) ÷ 3 × 1 + 160px = 190.61px

Flex 项目 D 计算后的宽度 =  ((1000px - 237.56px - 190.61px - 190.61px) - 160px × 2) ÷ 2 × 1 + 160px = 190.61px

Flex 项目 E 计算后的宽度 =  ((1000px - 237.56px - 190.61px - 190.61px - 190.61px) - 160px × 1) ÷ 1 × 1 + 160px = 190.61px
1
2
3
4
5
6
7

img

Demo 地址:https://codepen.io/airen/full/NWMjvym

接着再来看另一个情景,给所有 Flex 项目显式设置 flex:1 ,并且显式设置 width 或 inline-size 属性的值为 160px :

.item {
    flex: 1;
    width: 160px;
    
    /* flex 等同于 */
    flex-grow: 1;
    flex-shrink: 1;
    flex-basis: 0%;
}
1
2
3
4
5
6
7
8
9

通过前面的内容,我们可以知道,浏览器计算出来的 Flex 项目的 flex-basis 值将会是:

Flex 项目 A 的灵活性 = (Flex 容器的剩余空间  ÷ 所有 Flex 项目扩展因子 flex-grow 值总和 × 当前 Flex 项目自身的扩展因子 flex-grow

Flex 项目 A 的灵活性 = (1000px ÷ 5) × 1 = 200px

Flex 项目 A 计算后的宽度(flex-basis) = 0 + 200px = 200px

Flex 项目 B 计算后的宽度(flex-basis) = ((1000px - 200px)÷ 4) × 1 = 200px
Flex 项目 C 计算后的宽度(flex-basis) = ((1000px - 200px - 200px)÷ 3) × 1 = 200px
Flex 项目 D 计算后的宽度(flex-basis) = ((1000px - 200px - 200px - 200px)÷ 2) × 1 = 200px
Flex 项目 E 计算后的宽度(flex-basis) = ((1000px - 200px - 200px - 200px -200px)÷ 1) × 1 = 200px
1
2
3
4
5
6
7
8
9
10

这个示例中和前面只在 Flex 项目上显式设置 flex:1 有一点不同之处,那就是显式设置了 Flex 项目的宽度是 160px ,所以 Flex 项目 A 的 flex-basis 计算出来之后等于 200px ,它比 160px 大,这个时候浏览器将 flex-basis 计算后的值视为其宽度值。

img

Demo 地址: https://codepen.io/airen/full/WNJjZao

如果你将 width:160px 换成 width: 260px (它已经大于 Flex 项目 A 的 min-content 值)。你会发现,Flex 项目 A 的 flex-basis 计算出来之后是 200px ,但浏览器最终计算出来的 Flex 项目 A 宽度,最终以 Flex 项目 A 的内容的最小尺寸(min-content )为准,大约 237.52px 。

img

这两个示例告诉我们,当 Flex 项目显式设置了 flex:1 和具体的 width 值时,如果浏览器计算出来的 flex-basis 大于 Flex 项目的最小内容尺寸(min-content) 时,将以 flex-basis 计算出来的值作为 Flex 项目的宽度;反之,如果计算出来的 flex-basis 小于 Flex 项目的最小内容尺寸(min-content)时,浏览器会把 Flex 项目的最小内容尺寸(min-content)作为 flex-basis 的最终值,也将其作为该 Flex 项目的宽度。

你可以尝试着将 flex: 1 160px 和 width: 160px ,或 flex: 1 160px 和 width: 260px 运用到示例中的 Flex 项目上:

.item {
    flex: 1 160px;
    width: 160px;
    
    /* flex 属性等同于 */
    flex-grow: 1;
    flex-shrink: 1;
    flex-basis: 160px;
}

/* 或 */
.item {
    flex: 1 160px;
    width: 260px;
    
    /* flex 属性等同于 */
    flex-grow: 1;
    flex-shrink: 1;
    flex-basis: 160px;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

最终它的效果和在 Flex 项目上设置 flex:1 和 width: 160px 是等同的,只是计算出来的弹性量不同,但最终计算出来的 flex-basis 是一样的,它们都忽略了 Flex 项目的 width 。

img

Demo 地址: https://codepen.io/airen/full/XWqRVZd

这几个示例从侧面也回答了刚才提到的一点,为什么 flex:1 并不能在所有的场景中,让 Flex 项目均分 Flex 容器的空间。就这一点而言,W3C规范也是有相应描述的 (opens new window):

By default, flex items won’t shrink below their minimum content size (the length of the longest word or fixed-size element). To change this, set the min-width or min-height property.

大致的意思就是说,默认情况之下,Flex 项目(即设置了 flex:1 )在收缩的时候,其宽度也不会小于其最小内容尺寸(min-content)或固定尺寸元素。如果要改变这一点,需要在 Flex 项目上显示设置最小宽度 min-width (或 min-inline-size),或最小高度min-height(或min-block-size)的值,一般将其设置为0 。

你可能已经发现了,前面的示例有一个共同的特性,那就是 flex-basis 的值为 0 ,或者一个指定的长度值(<length-perentage>)。比如:

.item {
    flex: 1;
    
    /* 等同于 */
    flex-grow: 1;
    flex-shrink: 1;
    flex-basis: 0%; /* 浏览器将 flex-basis 计算为 0% */
}

.item {
    flex: 1 160px;
    
    /* 等同于 */
    flex-grow: 1;
    flex-shrink: 1;
    flex-basis: 160px; /* 显式指定 flex-basis 的值为 160px */
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

那么当 flex-basis 的值为 auto 的时候,Flex 项目又是如何计算的呢?

如果你在 Flex 项目显式设置了 flex: auto 时,相当于显式指定了 flex-basis 属性的值为 auto ,即:

.item {
    flex: auto; /* 等同于 flex: 1 auto */
    
    /* 等同于 */
    flex-grow: 1;
    flex-shrink: 1;
    flex-basis: auto;
}
1
2
3
4
5
6
7
8

当 flex-basis 取值为 auto 时,它的表现形式有点类似于元素的 width 或 inline-size 显式设置了值为 auto ,它的大小会根据元素的上下文或内容最大长度来决定。

但在 Flexbox 布局中,Flex 项目的 flex-basis 值为 auto 时,它的大小由 Flex 项目的最大内容长度(即 max-content)来决定。这个时候,示例中的每个 Flex 项目对应的 flex-basis 相当于 237.56px 、70.26px 、243.30px 、100.69px 和 100.11px 。

将相应的变量套到 flex-grow 计算公式中:

Flex 项目 A 的灵活性 = (Flex 容器的剩余空间  ÷ 所有 Flex 项目扩展因子 flex-grow 值总和 × 当前 Flex 项目自身的扩展因子 flex-grow

Flex 项目 A 的灵活性 = (1000px - 237.52px - 70.26px - 243.30px - 100.69px - 100.11px) ÷ 5 × 1 = 49.62px

Flex 项目 A 计算后的宽度(flex-basis) = 237.56px + 49.62px = 287.18px

Flex 项目 B 计算后的宽度(flex-basis) = (1000px - 287.18px - 70.26px - 243.30px - 100.69px - 100.11px) ÷ 4 × 1 + 70.26px = 119.88px
Flex 项目 C 计算后的宽度(flex-basis) = (1000px - 287.18px - 119.88px - 243.30px - 100.69px - 100.11px) ÷ 3 × 1 + 243.30px = 292.92px
Flex 项目 D 计算后的宽度(flex-basis) = (1000px - 287.18px - 119.88px - 292.92px - 100.69px - 100.11px) ÷ 2 × 1 + 100.69px = 150.31px
Flex 项目 E 计算后的宽度(flex-basis) = (1000px - 287.18px - 119.88px - 292.92px - 150.31px - 100.11px) ÷ 1 × 1 + 100.11px = 149.73px
1
2
3
4
5
6
7
8
9
10

img

Demo 地址: https://codepen.io/airen/full/XWqREWP

但当 flex-basis: auto 碰到 Flex 项目显式设置了长度尺寸,比如 width 或 inline-size 时,此时的 auto 计算出来的值就是对应的 width 或 inline-size 的值:

.item {
    flex: auto;
    width: 160px;
    
    /* 等同于 */
    flex-grow: 1;
    flex-shrink: 1;
    flex-basis: auto; /* 每个 Flex 项目的 flex-basis 初始值等于 width */
}
1
2
3
4
5
6
7
8
9

计算之后:

Flex 项目 A 的灵活性 = (Flex 容器的剩余空间  ÷ 所有 Flex 项目扩展因子 flex-grow 值总和 × 当前 Flex 项目自身的扩展因子 flex-grow

Flex 项目 A 的灵活性 = (1000px - 160px × 5) ÷ 5 × 1 = 40px

Flex 项目 A 计算后的宽度(flex-basis) = 160px + 40px = 200px

Flex 项目 B 计算后的宽度(flex-basis) = (1000px - 200px - 160px × 4) ÷ 4 × 1 + 160px = 200px
Flex 项目 C 计算后的宽度(flex-basis) = (1000px - 200px - 200px - 160px × 3) ÷ 3 × 1 + 160px = 200px
Flex 项目 D 计算后的宽度(flex-basis) = (1000px - 200px - 200px - 200px - 160px × 2) ÷ 2 × 1 + 160px = 200px
Flex 项目 E 计算后的宽度(flex-basis) = (1000px - 200px - 200px - 200px - 200px - 160px × 1) ÷ 1 × 1 + 160px = 200px
1
2
3
4
5
6
7
8
9
10

img

Demo 地址: https://codepen.io/airen/full/poVPLQx

其实 flex-grow 计算,还可以将上面的公式简化一下,但它有一个条件,即 设置了 flex 属性的 Flex 项目同时显式设置了 width 或 inline-size ,以及 flex-basis 属性值为 auto 时, 可以按下面这个简化公式计算每个 Flex 项目的尺寸:

img

前面所提到的 flex-grow 计算,都是基于flex 简写属性展开的,它们的计算和单独只在 Flex 项目上显式设置一个 flex-grow 属性还是有所不同的。比如:

.flex {
    flex: 1;
    
    /* 等同于 */
    flex-grow: 1;
    flex-shrink: 1;
    flex-basis:  0%; /* 浏览器计算值 */
}

.flex-grow {
    flex-grow: 1;
    
    /* 等同于 */
    flex-grow: 1;
    flex-shrink: 1; /* flex-shrink 的初始值为 1 */
    flex-basis: auto; /* flex-basis 的初始值为 auto */
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

仅在 Flex 项目显式设置 flex-grow 一个属性时,它的计算方式类似于 flex: auto :

img

Demo 地址: https://codepen.io/airen/full/ZEoKoJY

除此之外,可以根据需要给每个 Flex 项目的 flex-grow 属性设置不同的值。比如:

.item {
    flex-grow: var(--flex-grow, 0);
}

.item:nth-child(1) {
    --flex-grow: 0;
}

.item:nth-child(2) {
    --flex-grow: 1;
}

.item:nth-child(3) {
    --flex-grow: 2;
}

.item:nth-child(4) {
    --flex-grow: 3;
}

.item:nth-child(5) {
    --flex-grow: 4;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

Flex 项目的 flex-grow 设置不同的值时,表示每个 Flex 项目的扩展比率是不相同的,也就是说瓜分 Flex 容器剩余空间就不相等了。flex-grow 值越大,所占的比例就越大 。我们分别来看,flex-grow 取值不同时,它的计算:

Flex 项目的 flex-grow 总和 =  (0 + 1 + 2 + 3 + 4) = 10
Flex 项目的灵活性 = (Flex 容器的剩余空间  ÷ 所有 Flex 项目扩展因子 flex-grow 值总和 × 当前 Flex 项目自身的扩展因子 flex-grow

// 案例1
// Flex 项目的 flex-basis: auto; 

Flex 项目 A 的弹性值 = (1000px - 237.52px - 70.26px - 243.30px - 100.69px - 100.11px) ÷ (0 + 1 + 2 + 3 + 4) × 0 = 0px
Flex 项目 A 计算后的 flex-basis 值 = 237.52px + 0 = 237.52px

Flex 项目 B 的弹性值 = (1000px - 237.52px - 70.26px - 243.30px - 100.69px - 100.11px) ÷ (1 + 2 + 3 + 4) × 1 = 24.81px
Flex 项目 B 计算后的 flex-basis 值 = 70.26px + 24.81px = 95.07px

Flex 项目 C 的弹性值 = (1000px - 237.52px - 95.07px - 243.30px - 100.69px - 100.11px) ÷ (2 + 3 + 4) × 2  = 49.62px
Flex 项目 C 计算后的 flex-basis 值 = 243.30px + 49.62px = 292.92px

Flex 项目 D 的弹性值 = (1000px - 237.52px - 95.07px - 292.92px - 100.69px - 100.11px) ÷ (3 + 4) × 3 = 74.44px
Flex 项目 D 计算后的 flex-basis 值 = 100.69px + 74.44px = 175.13px

Flex 项目 E 的弹性值 = (1000px - 237.52px - 95.07px - 292.92px - 175.13px - 100.11px) ÷ 4 × 4  = 99.25px
Flex 项目 E 计算后的 flex-basis 值 = 100.11px + 99.25px = 199.36px

// 案例2
// Flex 项目的 flex-basis: auto; width: 160px

Flex 项目 A 的弹性值 = (1000px - 160px × 5) ÷ (0 + 1 + 2 + 3 + 4) × 0 = 0px
Flex 项目 A 计算后的 flex-basis 值 = 160px + 0 = 160px

Flex 项目 B 的弹性值 = (1000px - 160px - 160px × 4) ÷ (1 + 2 + 3 + 4) × 1 = 20px
Flex 项目 B 计算后的 flex-basis 值 = 160px + 20px = 180px

Flex 项目 C 的弹性值 = (1000px - 160px - 180px - 160px × 3) ÷ (2 + 3 + 4) × 2 = 40px
Flex 项目 C 计算后的 flex-basis 值 = 160px + 40px = 200px

Flex 项目 D 的弹性值 = (1000px - 160px - 180px - 200px - 160px × 2) ÷ (3 + 4) × 3 = 60px
Flex 项目 D 计算后的 flex-basis 值 = 160px + 60px = 220px

Flex 项目 E 的弹性值 = (1000px - 160px - 180px - 200px - 220px - 160px) ÷ 4 × 4 = 80px
Flex 项目 E 计算后的 flex-basis 值 = 160px + 80px = 240px

// 案例1和2对应的 Demo 地址: https://codepen.io/airen/full/GRdmdbw


// 案例3
// Flex 项目的 flex-basis: 0;

Flex 项目 A 的弹性值 = 1000 ÷ (0 + 1 + 2 + 3 + 4) × 0 = 0px
Flex 项目 A 计算后的 flex-basis 值 = 237.5px + 0 = 237.5px (Flex 项目 A 的 min-content)

Flex 项目 B 的弹性值 = (1000px - 237.5px) ÷ (1 + 2 + 3 + 4) × 1  = 76.25px
Flex 项目 B 计算后的 flex-basis 值 = 70.25px + 0 = 70.25px

Flex 项目 C 的弹性值 = (1000px - 237.5px - 76.25px) ÷ (2 + 3 + 4) × 2  = 152.5px
Flex 项目 C 计算后的 flex-basis 值 = 152.5px + 0 = 152.5px

Flex 项目 D 的弹性值 = (1000px - 237.5px - 76.25px - 152.5px) ÷ (3 + 4) × 3 = 228.75px
Flex 项目 D 计算后的 flex-basis 值 = 228.75px + 0 = 228.75px

Flex 项目 E 的弹性值 = (1000px - 237.5px - 76.25px - 152.5px - 228.75px) ÷ 4 × 4  = 305px
Flex 项目 E 计算后的 flex-basis 值 =  305px + 0 = 305px

// 案例4
// Flex 项目的 flex-basis: 0; width: 160px

Flex 项目 A 的弹性值 = 1000px ÷ (0 + 1 + 2 + 3 + 4) × 0 =0px
Flex 项目 A 计算后的 flex-basis 值 = 160px + 0 = 160px (Flex项目 A 不扩展,取其 width 值)

Flex 项目 B 的弹性值 = (1000px - 160px) ÷ (1 + 2 + 3 + 4) × 1  = 84px  
Flex 项目 B 计算后的 flex-basis 值 = 84px + 0 = 84px

Flex 项目 C 的弹性值 = (1000px - 160px - 84px) ÷ (2 + 3 + 4) × 2 = 168px
Flex 项目 C 计算后的 flex-basis 值 = 168px + 0 = 168px

Flex 项目 D 的弹性值 = (1000px - 160px - 84px - 168px) ÷ (3 + 4) × 3  = 252px
Flex 项目 D 计算后的 flex-basis 值 = 252px + 0 = 252px

Flex 项目 E 的弹性值 = (1000px - 160px - 84px - 168px - 252px) ÷ 4 × 4  = 336px
Flex 项目 E 计算后的 flex-basis 值 = 336px + 0 = 336px

// 案例3 和 4 对应的 Demo 地址:https://codepen.io/airen/full/bGMRpZp 


// 案例5
// 所有 Flex 项目的 flex-basis: 160px

Flex 项目 A 的弹性值 = (1000px - 160px × 5) ÷ (0 + 1 + 2 + 3 + 4) × 0 = 0px
Flex 项目 A 计算后的 flex-basis = 237.5px + 0 = 237.5px (不扩展,取其内容最小尺寸 min-content)

Flex 项目 B 的弹性值 = (1000px - 237.5px - 160px × 4) ÷ (1 + 2 + 3 + 4) × 1 = 12.25px
Flex 项目 B 计算后的 flex-basis 值 = 160px + 12.25px = 172.25px

Flex 项目 C 的弹性值 = (1000px - 237.5px - 172.25px - 160px × 3) ÷ (2 + 3 + 4) × 2 = 24.5px
Flex 项目 C 计算后的 flex-basis 值 = 160px + 24.5px = 184.5px

Flex 项目 D 的弹性值 = (1000px - 237.5px - 172.25px - 184.5px - 160 × 2) ÷ (3 + 4) × 3 = 36.75px
Flex 项目 D 计算后的 flex-basis 值 = 160px + 36.75px = 196.75px

Flex 项目 E 的弹性值 = (1000px - 237.5px - 172.25px - 184.5px - 196.75px - 160px) ÷ 4 × 4 = 49px 
Flex 项目 E 计算后的 flex-basis 值 = 160px + 49px = 209px

// 案例6
// 所有 Flex 项目的 flex-basis: 160px; width: 160px
Flex 项目 A 的弹性值 = (1000px - 160px × 5) ÷ (0 + 1 + 2 + 3 + 4) × 0 = 0px
Flex 项目 A 计算后的 flex-basis = 160px + 0 = 160px (不扩展,取其 width 属性值)

Flex 项目 B 的弹性值 = (1000px - 160px - 160px × 4) ÷ (1 + 2 + 3 + 4) × 1 = 20px
Flex 项目 B 计算后的 flex-basis 值 = 160px + 20px = 180px

Flex 项目 C 的弹性值 = (1000px - 160px - 180px - 160px × 3) ÷ (2 + 3 + 4) × 2 = 40px
Flex 项目 C 计算后的 flex-basis 值 = 160px + 40px = 200px

Flex 项目 D 的弹性值 = (1000px - 160px - 180px - 200px - 160px × 2) ÷ (3 + 4) × 3 = 60px
Flex 项目 D 计算后的 flex-basis 值 = 160px + 60px = 220px

Flex 项目 E 的弹性值 = (1000px - 160px - 180px - 200px - 220px - 160px) ÷ 4 × 4 = 80px
Flex 项目 E 计算后的 flex-basis 值 = 160px + 80px = 240px

// 案例 5 和 6 的 Demo 地址: https://codepen.io/airen/full/GRdEqqp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117

在给 Flex 项目设置 flex-grow 属性的值时,除了像前面的示例展示的那样,设置一个正整数 之外,还可以给 flex-grow 设置一个小数值 ,比如:

// Demo 1:
.item {
    flex-grow: .1;
    
    /* 等同于 */
    flex-grow: .1;
    flex-shrink: 1;
    flex-basis: auto;
}

// Demo 2:
.item {
    flex-grow: var(--flex-grow, .1);
}

.item:nth-child(2) {
    --flex-grow: .2;
}

.item:nth-child(3) {
    --flex-grow: .3;
}

.item:nth-child(4) {
    --flex-grow: .4;
}

.item:nth-child(5) {
    --flex-grow: .5;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

上面两个示例中,第一个示例中的所有 Flex 项目的 flex-grow 属性的值和是 0.5(即 0.1 + 0.1 + 0.1 + 0.1 + 0.1 = 0.5 ),它们(flex-grow )的总和小于 1 ;第二个示例中的所有 Flex 项目的 flex-grow 属性的值和是 1.5 (即 0.1 + 0.2 + 0.3 + 0.4 + 0.5 = 1.5),它们(flex-grow)的总和大于 1 。

两者最大的差异就是 所有 Flex 项目的 flex-grow 总和如果小于 1 ,Flex 容器剩余空间还会有余留; flex-grow 大于或等于1时,Flex 容器的剩余空间不会有余留 :

img

可能有同学会问,flex-grow 取值为小数值时,它又是如何计算呢?

它的计算分两种情况,当所有 Flex 项目 flex-grow 值的和小于 1 时,将按照下面的公式来计算:

img

由于 Flex 容器的剩余空间分不完,所以不需要像前面的示例那样去循环遍历每一个 Flex 项目。简单地说,当所有 Flex 项目的 flex-grow 属性值的总和小于等于 1 时, Flex 项目的灵活性(弹性值 Flexibility)会等于 Flex 容器的剩余空间乘以当前 Flex 项目自身的扩展因子 flex-grow 值:

Flex 项目的 flex-grow 总和 =  (0.1 + 0.1 + 0.1 + 0.1 + 0.1) = 0.5 < 1
Flex 项目的灵活性 = (Flex 容器的剩余空间  × 当前 Flex 项目自身的扩展因子 flex-grow
Flex 容器的剩余空间 = 1000px - 237.52px - 70.26px - 243.30px - 100.69px - 100.11px = 248.12px

Flex 项目 A 的弹性值 = 248.12px × 0.1 = 24.81px
Flex 项目 A 计算后的 flex-basis 值 = 237.52px + 24.81px = 262.33px

Flex 项目 B 的弹性值 = 248.12px × 0.1 = 24.81px
Flex 项目 B 计算后的 flex-basis 值 = 70.26px + 24.81px = 95.07px

Flex 项目 C 的弹性值 = 248.12px × 0.1 = 24.81px
Flex 项目 C 计算后的 flex-basis 值 = 243.30px + 24.81px = 268.11px 

Flex 项目 D 的弹性值 = 248.12px × 0.1 = 24.81px
Flex 项目 D 计算后的 flex-basis 值 = 100.69px + 24.81px = 125.5px

Flex 项目 E 的弹性值 =  248.12px × 0.1 = 24.81px
Flex 项目 E 计算后的 flex-basis 值 = 100.11px + 24.81px = 124.92px
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

img

Demo 地址: https://codepen.io/airen/full/eYrRdLN

将上面示例稍微调整一下,让它们的 flex-grow 值的总和等于1 :

.item {
    flex-grow: var(--flex-grow, 0);
}

.item:nth-child(2) {
    --flex-grow: .2;
}

.item:nth-child(3) {
    --flex-grow: .2;
}

.item:nth-child(4) {
    --flex-grow: .3;
}

.item:nth-child(5) {
    --flex-grow: .3;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

它的计算和所有 Flex 项目的 flex-grow 值总和小于1 的计算方式是一样的:

Flex 项目的 flex-grow 总和 =  (0 + 0.2 + 0.2 + 0.3 + 0.3) = 1
Flex 项目的灵活性 = (Flex 容器的剩余空间  × 当前 Flex 项目自身的扩展因子 flex-grow
Flex 容器的剩余空间 = 1000px - 237.52px - 70.26px - 243.30px - 100.69px - 100.11px = 248.12px

Flex 项目 A 的弹性值 = 248.12px × 0 = 0px
Flex 项目 A 计算后的 flex-basis 值 = 237.52px + 0px = 237.52px

Flex 项目 B 的弹性值 = 248.12px × 0.2 = 49.62px
Flex 项目 B 计算后的 flex-basis 值 = 70.26px + 49.62px = 119.88px

Flex 项目 C 的弹性值 = 248.12px × 0.2 = 49.62px
Flex 项目 C 计算后的 flex-basis 值 = 243.30px + 49.62px = 292.92px 

Flex 项目 D 的弹性值 = 248.12px × 0.3 = 74.44px
Flex 项目 D 计算后的 flex-basis 值 = 100.69px + 74.44px = 175.13px

Flex 项目 E 的弹性值 =  248.12px × 0.3 = 74.44px
Flex 项目 E 计算后的 flex-basis 值 = 100.11px + 74.44px = 174.55px
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

img

Demo 地址: https://codepen.io/airen/full/oNdwBWK

当然,flex-grow 取值小于 1 时,它们的总和也有可能会是大于1 的,比如:

.item {
    flex-grow: var(--flex-grow, .1);
}

.item:nth-child(2) {
    --flex-grow: .2;
}

.item:nth-child(3) {
    --flex-grow: .3;
}

.item:nth-child(4) {
    --flex-grow: .4;
}

.item:nth-child(5) {
    --flex-grow: .5;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

当所有 Flex 项目的 flex-grow 属性值总和大于 1 时,对于 flex-grow 的计算就需要用到前面所说的循环遍历的方式来计算了:

Flex 项目的 flex-grow 总和 =  (0.1 + 0.2 + 0.3 + 0.4 + 0.5) = 1.5 > 1
Flex 项目的灵活性 = (Flex 容器的剩余空间  ÷ 所有 Flex 项目扩展因子 flex-grow 值总和 × 当前 Flex 项目自身的扩展因子 flex-grow

Flex 容器的剩余空间 = 1000px - 237.52px - 70.26px - 243.30px - 100.69px - 100.11px = 248.12px

Flex 项目 A 的弹性值 = (1000px - 237.52px - 70.26px - 243.30px - 100.69px - 100.11px) ÷ (0.1 + 0.2 + 0.3 + 0.4 + 0.5) × 0.1 = 16.54px
Flex 项目 A 计算后的 flex-basis 值 = 237.52px + 16.54px = 254.06px

Flex 项目 B 的弹性值 = (1000px - 254.06px - 70.26px - 243.30px - 100.69px - 100.11px) ÷ (0.2 + 0.3 + 0.4 + 0.5) × 0.2 = 33.08px
Flex 项目 B 计算后的 flex-basis 值 = 70.26px + 33.08px = 103.34px

Flex 项目 C 的弹性值 = (1000px - 254.06px - 103.34px - 243.30px - 100.69px - 100.11px) ÷ (0.3 + 0.4 + 0.5) × 0.3 = 49.63px
Flex 项目 C 计算后的 flex-basis 值 = 243.30px + 49.63px = 292.93px 

Flex 项目 D 的弹性值 = (1000px - 254.06px - 103.34px - 292.93px - 100.69px - 100.11px) ÷ (0.4 + 0.5) × 0.4 = 66.16px
Flex 项目 D 计算后的 flex-basis 值 = 100.69px + 66.16px = 166.85px

Flex 项目 E 的弹性值 =  (1000px - 254.06px - 103.34px - 292.93px - 166.85px - 100.11px) ÷  0.5  × 0.5 = 82.71px
Flex 项目 E 计算后的 flex-basis 值 = 100.11px + 82.71px = 182.82px
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

img

Demo 地址: https://codepen.io/airen/full/NWMgdza

如此一来,Flexbox 布局中的 flex-grow 计算公式就分为两个部分:

img

再次强制一下,当所有 Flex 项目的 flex-grow 属性值总和小于 1 时,Flex 容器剩余空间是分不完的 :

img

# 小结

有关于 Flex 项目中 flex-grow 计算,暂时就和大家聊到这里了。这里简单总结一下:

  • 只有 Flex 容器有剩余空间,且 flex-grow 值不为 0 时,Flex 项目才会按照扩展因子(flex-grow 值)比率来分割 Flex 容器的剩余空间。
  • 如果 Flex 容器中所有 Flex 项目的 flex-grow 值的总和小于 1 时,Flex 容器的剩余空间是分不完的(有留存),只有 flex-grow 值的总和大于或等于 1 时,Flex 容器的剩余空间才能全部分完。
  • Flex 容器中的所有 Flex 项目的 flex-grow 值设置为 1 ,并不能平均分配 Flex 容器的剩余空间,它和 Flex 项目自身的内容最小尺寸以及它的内部固定尺寸的元素有关。
  • Flex 项目的 flex-grow 会给 Flex 项目的 flex-basis 值带来变化,但它也会受 min-* (比如 min-width 、 min-inline-size 、min-height 、min-block-size)和 max-* (比如 max-width 、max-inline-size 、max-height 和 max-block-size )等属性的影响。

在这一节中,我们一起探讨了如何通过扩展因子比例 flex-grow 来分配 Flex 容器的剩余空间,从而扩展 Flex 项目尺寸。但在实际使用的时候,Flex 容器除了有剩余空间情景之外,也还会存在不足空间的情景。 Flex 容器存在不足空间时,我们可以通过 flex 的另一个特性 flex-shrink 收缩因子来收缩 Flex 项目,从而让 Flex 项目填满整个 Flex 容器。

编辑 (opens new window)
上次更新: 2023/08/06, 00:38:41
05Flexbox 布局中的 flex 属性的基础运用
07Flexbox 中的计算:通过收缩因子比例收缩 Flex 项目

← 05Flexbox 布局中的 flex 属性的基础运用 07Flexbox 中的计算:通过收缩因子比例收缩 Flex 项目→

最近更新
01
课件-react路由-V6
01-22
02
课件-国际化
01-22
03
课件-redux-toolkit
01-22
更多文章>
Theme by Vdoing | Copyright © 2019-2024 Evan Xu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式