当前位置: 首页 > 知识库问答 >
问题:

前端 - 为什么这个flex布局中 前2个flex子元素没有分配到剩余空间?

华温书
2024-05-08
<div class="container">  <div class="item">abdfdofewefdfdsdfewfwefdf</div>  <div  class="item"><img src="https://demo.cssworld.cn/new/images/nature-8.jpg"></div>  <div class="item">务开发时遇到的,为了便于清晰描述,我这里写了一个能复现上述问d题的简化</div></div>
.container {  display: flex;  flex-wrap: wrap;  width: 420px;  border: 1px green solid;}.item {  flex: 1;  border: 1px blue dotted;}img[src*="nature"] {  width: 100px;}

image.png

问题: flex:1 等价于 flex: 1 1 0%, 既然flex-basis是0%,那么flex子元素 应该优先使用最小内容宽度吧,第一个子元素的最小内容宽度就是 文本 abdfdofewefdfdsdfewfwefdf的宽度,
第二个flex子元素的最小内容宽度就是图片本身的宽度100px,
第三个flex子元素的最小内容宽度 应该是单个中文字符的宽度吧?
所以剩余空间=flex容器宽度-三个flex子元素的最小内容宽度

然后把这个剩余空间等比例分配给每一个子元素, 所以我理解中的 渲染效果应该是类似下图:
image.png
每一个绿色框框都是一个flex子元素
红色框框部分是 该flex子元素 分配到的 剩余空间。

然而实际渲染的结果 看起来好像剩余空间 都给了第三个flex子元素,请问我的理解错在了哪里?

共有3个答案

贝成业
2024-05-08

把第一个元素的文本变短一点。因为flex-basisc:0%flex-grow: 1并且三个元素的最小内容宽度都小于这个平分大小,所以最后这三个元素都占据相同的宽度。(对比一下当前最后一个元素的宽度和题目中最后一个元素的宽度,发现它变小了)
image.png

当我们不断增加第一个元素的文本长度,当它刚好大于此时这个宽度时,由于它的大小不能小于最小内容宽度,所以后面两个元素开始缩小(后两个大小此时还是大于它们的最小内容宽度的)
image.png

当第二个元素缩小到它的最小内容宽度时(最后一个元素此时还没有缩小到最小内容宽度)
image.png

之后再增加第一个元素的文本长度,只有第三个元素收缩
image.png

当第三个元素收缩到其最小内容宽度的时候,就不再收缩了,再增加第一个元素的文本长度,就溢出了(在.container上添加overflow: hidden
image.png

阴元青
2024-05-08
好问题! 昨天晚上看到就想回答了,太晚,直接睡了。

接下来,拆解这个问题。 所有术语表述的前提是flex-direction为row。

flex:1 等价写做 flex-grow:1; flex-shrink:1; flex-basis:0%,开始实验。

第一步,先将flex-grow、flex-shrink注释掉,理解flex-basis

  • 子容器的这个属性用于在 grow或shrink “初步” 计算时使用,我们暂称它为 “计算宽度
  • flex-basis:0% 即表示在做初步计算时,该子容器的宽度是0,即计算宽度是0
  • flex-basis:0% 对应子容器还有个 ”最小呈现宽度“, 是其放入内容后的最小宽度。 稍后空间”分赃“计算时会用到。下图展示了本例各子容器的最小呈现宽度。
    image.png

题外话:这里有个意外的知识点,看第三个子容器,都是中文,最小宽度为什么是两个字,不应该是1个汉字才合理么? 出现两个汉字是因为文字中含有全角的标点符号,系统在排版时会将标点符号强行与前面的字放在一行,即有一行占据了两个字符,整体就会以最长的行作为宽度呈现。感兴趣的人可以去掉其中的所有逗号,你会发现变成是一个字一行了。
image.png

第二步,打开flex-grow的注释

系统将进行扩张计算

  1. 计算子容器的 ”最小呈现宽度“ 之和, 211.54+2+110+2+32+2 = 359.54px,小于父容器宽度420px,所以这三个子元素都将会在第一行参与扩张。
  2. 初步排布:根据 “计算宽度” 为0%(为简化问题,我们先不考虑border),余下待被瓜分的宽度420px会被等分成三份,每份140px。
  3. 排布调整:

    1. 先调整“最小呈现宽度”最大的子容器,这里是子容器1,它的“最小呈现宽度” 213.54px(加上边框的2px了),大于初步排布的140,将给与 213.54px。余下 206.46px (420-213.54) 均分两份,每份空间103.23 给与子容器2和子容器3.
    2. 在调整“最小呈现宽度”次大的子容器2,112px(110+2),大于103.23,则给与子容器2 112px的宽度,剩余 94.46px
    3. 最后剩余空间全部留给子容器3 (它的“最小呈现宽度”是38px,小于94.46px)

本例不会牵涉到 flex-shrink,所以不再讨论之。

刘英彦
2024-05-08

如果 flex-basis 明确设置了,那么剩余空间的大小就是容器的大小减去每一个元素的 flex-basis 大小。如果 flex-basis 没有明确设置,那么会从元素的 width, max-width, max-content 等属性中确定元素的 flex-basis 大小。

这里的每一个元素的 flex-basis 都为 0%,因此剩余空间的大小就是容器的宽度大小减去元素的边框大小。由于每一个元素的的 flex-grow 都是 1,那么每一个元素分配的大小就是 (420 - 3 x 2) / 3 = 138。由于第一个元素其首选最小宽度大于 138,当分配的大小小于该大小时取首选最小宽度,因此第一个元素会占据大约 218.48(可能会因为浏览器的默认使用字体不同有所变化,包括了边框大小)。这会导致剩余空间的大小重新计算,因此剩余两个元素的分配大小变为 (420 - 218.48 - 2 x 2) / 2 = 98.76。同样的原因会导致第二个元素取其首选最小宽度,也就是 100,如果包括边框,那么第二个元素的大小就占据 102。这样最后一个元素分配的大小变为 420 - 218.48 - 102 - 1 x 2 = 97.52,如果加上边框就是 99.52。

简单来说就是最小内容宽度不是用来确定剩余空间的,而是用来约束最终元素的大小的。如果希望让计算更加直观,最好把子元素的边框删除,这样计算起来简单一点。

 类似资料:
  • WeUI提供了快速的 flex 布局 示例代码 <template> <div class="page"> <div class="page__bd page__bd_spacing"> <div class="weui-flex"> <div class="weui-flex__item"> <div class="placeholde

  • 参考 Flex 布局教程:语法篇

  • Flex是Flexible Box的缩写,意为“弹性布局”,2009年它由W3C提出了一种新的网页布局方案。QAP也支持flex布局。目前flex支持的容器属性有:flexDirection、flexWrap、justifyContent、alignItems、width和height等属性。 flexDirection flexDirection属性决定了主轴的方向,它有两个值(不支持row-r

  • 为什么这里的 flex-direction 和 align-item 还有效 firefox 上一切正常 jsfiddle 浏览器信息: Vivaldi 6.2.3105.58 (Stable channel) stable (64 位) Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/11

  • Fixed 盒子数量不是固定的 Fixed 盒子宽度是固定的 Fill 盒子只有一个 Fill 盒子宽度是动态的 如何让 Fill 填满剩余 Container 的宽度? 如下图

  • 演示Demo 图中 一个flex容器内部有四个div元素, div内部的img的宽度设置为100px。 默认情况下flex-wrap=nowrap flex子项会一行显示且不允许换行,因此可能会出现宽度溢出的问题。 问题1 “因此可能会出现宽度溢出的问题” : 这个宽度溢出应该也是有 条件的吧? 虽然flex子项的累计宽度大于flex容器,但是默认情况下 flex子项是允许收缩的。 如果收缩以后还