那些年Flex弹性布局中你所迷惑的点

前言闲话:

好久好久,没有写博文了,此处批评下懒惰的自己,哈哈~。为啥突然写这篇文章呢,是因为前几天我刷题,正好刷到flex相关求长度的题目,结果算错了,虽然平时写了很多布局页面,但是感觉自己这块还是理解不够深刻,后面看了很多不同人的题目解析,自己也从中有了一些收获心得,必要总结一下吧,自我学习,如有幸帮助到其他人,我也会很开心。

关于Flex弹性布局迷惑点,我暂时从两大点进行阐述

迷惑1:flex属性简写迷惑

日常写页面布局的时候,对于Flex布局,我们一般都会用flex属性来简写其弹性盒子项(flex item)的三个属性:

  • flex-grow
  • flex-shrink
  • flex-basis

下面我列出了常见的几类简写形式,其中我觉得特别容易记错的就是单值简写,例如flex: 1flex: autoflex: none代表什么?这类的问题…反正我之前有时候老记错他们的默认值,汗-_-||

 /*单值简写*/
 flex: none; /* flex: 0 0 auto */
 flex: 1; /* flex: 1 1 0% */
 flex: 2; /* flex: 2 1 0% */
 flex: 100px; /* flex: 1 1 100px */
 flex: 50%; /* flex: 1 1 50% */
 flex: auto; /* flex: 1 1 auto */

 /*双值简写*/
 flex: 1 2; /* flex: 1 2 0% */
 flex: 1 100px; /* flex: 1 1 100px */
 flex: 1 50%; /* flex: 1 1 50% */
 flex: 1 auto; /* flex: 1 1 auto */

 /*三值简写*/
 flex: 2 1 auto; /* flex: 1 1 0% */
 flex: 2 1 0%; /* flex: 2 1 0% */
 flex: 2 1 100px; /* flex: 2 1 100px */

嗯,看完了是吗?那我们简单的说一下这三个属性吧(提倡简写,所以请大家熟记默认值)

flex-grow 属性表示弹性盒子项(flex item)的拉伸因子,即放大比例,默认值为0,表示如果存在剩余空间,也不放大。
注意 不允许为负值

flex-shrink 属性表示弹性盒子项(flex item)的收缩因子,即缩小比例,默认为1,表示如果空间不足,该项目将缩小。
注意 不允许为负值

flex-basis 属性表示弹性盒子项(flex item)在主轴方向上的初始大小或者叫本来大小(官方术语:分配多余空间之前,项目占据的主轴空间)。根据这个属性,计算主轴是否有多余空间,它的默认值为auto
注意 不允许为负值

再补充一句:flex-basis 的值可以是数字带绝对单位例如 px; 也可以是一个百分数,百分数是相对于其父弹性盒容器的宽或者高(取决于主轴的方向)计算。如果不使用 box-sizing 来改变盒模型的话,那么这个属性就决定了 flex 元素的内容盒(content-box)的宽或者高(取决于主轴的方向,即父元素的flex-direction的设置)的尺寸大小。

具体详细关于Flex布局的介绍语法,温习或者学习请移步戳大牛文章,阮一峰: Flex 布局教程:语法篇.文章很详细,反正我之前忘记了就去看一眼,哈哈

迷惑2:flex属性计算迷惑

其实概念可能大家都懂,但是碰到相关的计算时,就容易发蒙。了解其真正的计算规则和方法,才能让我们真正的理解和更好的使用,下面我就以题目的形式,分析解决一些关于flex属性的计算迷惑

举例:两列左右布局,如left和right

<div class="container">
  <div class="left"></div>
  <div class="right"></div>
</div>

问题:求 leftright 的实际宽度?

情况1(存在剩余空间,item项目放大)
* {
   padding: 0;
   margin: 0;
 }
 .container {
   width: 600px;
   height: 50px;
   display: flex;
 }
 .left {
   flex: 1; /* 1 1 0% */
   background: red;
 }
 .right {
   flex: 2; /* 2 1 0% */
   background: blue;
 }

这个比较简单,大多数人都可以很快做出来,因为left占1份,right占2份,所以如下计算:

// 父容器 width: 600px
let widthLeft = 600px * 1/3 = 200px;
let widthRight = 600px * 2/3 = 400px;

但是,如果稍微改一下题目,更改left如下

left {
	width: 300px
	flex: 1; /* 1 1 0% */
   	background: red;
}
/*再或者这样*/
left {
	width: 300px
	flex: auto; /* 1 1 0% */
   	background: red;
}

那结果是什么呢?widthLeft是多少?widthRight 是多少?如果此刻的你依然可以准确快速算出,那恭喜你,说明你已经真正理解flex其中的计算,但如果有小伙伴会感到一点点蒙,那建议你耐心往下看。
题外话:当然实践是检验真理的最好方式,放到浏览器里跑一下,大家就知道结果了,但是如果这是在笔试做题或者无电脑的环境中呢?如何准确作答?

先分析第一题:

left只设置 flex: 1;

left设置flex:1,即flex: 1 1 0%; right设置flex:2,即flex: 2 1 0%,之前理解的总空间里left占1份,right占2份,没有问题,但是flex-basis: 0%这个表示弹性盒子项item初始大小为 0% * 600px = 0px,即初始大小为0,又因为left的flex-grow:1,right的flex-grow:2,那left和right的实际宽度就是初始长度 + 放大长度

// 父容器 width: 600px
let basisWid = 0;
let leftGrowWid = 600px * 1/3 = 200px; // left的放大比例长度
let rightGrowWid = 600px * 2/3 = 400px; // right的放大比例长度
let widthLeft = basicWid + leftGrowWid = 200px; // left实际长度
let widthRight = basicWid + rightGrowWid = 400px; // right实际长度

在这里插入图片描述
题目变形1:

left设置 width: 300px;
其实,这里的width:300px是一个干扰条件,用来专门迷惑你的,它有和没有结果都是一样的。计算的思路还是和上面一样,答案不变。

题目变形2:

left设置 width: 300px;
left更改为 flex: auto;
现在情况不一样了,left的flex属性变为了auto,即flex: 1 1 auto, flex-basis为auto的表示会按照left的设置宽度进行计算,因为left的宽度现在为300px,那么left就要按照当前300px的基础上进行放大,所以:

// 父容器 width: 600px
let leftBasisWid = 300px; // left初始因为为flex-basis为auto,所以取决于left的width
let rightBasisWid = 0; // right初始大小依然为0
let leftSpace = 600px - 300px = 300px; // 剩余空间大小
let leftGrowWid = leftSpace * 1/3 = 100px; // left的放大比例长度
let rightGrowWid = leftSpace * 2/3 = 200px; // right的放大比例长度
let widthLeft = leftBasisWid + leftGrowWid = 400px; // left实际长度
let widthRight = rightBasisWid + rightGrowWid = 200px; // right实际长度

在这里插入图片描述
这里你需要记住3点:

  1. 只要父元素设置了Flex布局,并且子元素(弹性盒子item)设置了flex属性,那item的的长或宽就会受其影响
  2. flex-basis只要为0%,那item设置了长度也无效
  3. flex-basis只要为auto,那item设置了长度就会作为它的初始长度
情况2(剩余空间不足,item项目缩小)
* {
   padding: 0;
   margin: 0;
 }
 .container {
   width: 600px;
   height: 50px;
   display: flex;
 }
 .left {
   flex: 1 2 500px;
   background: red;
 }
 .right {
   flex: 2 1 400px;
   background: blue;
 }

这个就是另一种情况了,情况1的学习中大家应该知道如何判断,空间到底是富裕还是不足了吧。这题可以明显可以看出父容器的空间不足(left和right的初始宽度之和大于600),那这时候,对于left和right的实际长度就是flex-shrink在参与计算,发挥作用。

可能有些小伙伴会这样分析计算:

1.left容器 放大比例1,缩小比例 2 默认占500px
2.right容器 放大比例2,缩小比例 1 默认占400px

当子项目宽度总和大于父容器宽度时,如果有缩小比例将按照缩小比例进行压缩,比如子项目总和900px大于父容器600px,多出的300px将按照缩小比例进行压缩
left容器将会压缩2/3* 300 = 200px
right容器将会压缩1/3* 300 =100px
所以最终left和right宽度都是300px

同理当子项目宽度总和小于父容器宽度时,如果有放大比例将按照放大比例进行扩张。

但是实际把代码放到浏览器运行下,发现结果并不是200和100,而是left:285.72px,right:314.28px
在这里插入图片描述
注意 弹性盒子item的缩小计算放大计算要稍微复杂一些,但是搞清楚后,一样信手拈来。上面提到的“同理当子项目宽度总和小于父容器宽度时,如果有放大比例将按照放大比例进行扩张。”这个是对的,但是子项目宽度总和大于父容器宽度时,计算不能想上面那样,是错误的,毕竟浏览器是不会骗你的。

解析:首先,left和right的flex-shrink分别为2和1,flex-basis分别为500px和400px,则我们可以知道(500 + 400 > 600),剩余空间不足,项目会溢出300,但是因为此时left和right都会收缩,所以收缩值需要先计算,最终长度应该等于:item初始长度 - 收缩长度

// 父容器 width: 600px,left初始长度500px,right初始长度为400px
let leftBasisWid = 500px; // left初始因为为flex-basis为500px
let rightBasisWid = 400px; // right初始因为为flex-basis为400px
let overSpace = (500px + 400px) - 600px = 300px; // 剩余空间不足,溢出空间为300px
let totalWeight = 2 * 500 + 1 * 400 = 1400; // 总权重值(2和1为left和right的flex-shrink值)
let leftRatio = 2 * 500 / totalWeight; // left的收缩比
let rightRatio = 1 * 400 / totalWeight; // right的收缩比
let leftShrinkWid = overSpace * leftRatio  = 214.28px; // left的缩小比例长度
let rightShrinkWid = overSpace * rightRatio  = 85.72px; // right的缩小比例长度
let widthLeft = leftBasisWid - leftShrinkWid = 285.72px; // left实际长度
let widthRight = rightBasisWid - rightShrinkWid = 314.28px; // right实际长度

举例:三列左右布局,如left middle right

上题基础上多增加一个middle,left和right样式还保持不变

<div class="container">
   <div class="left"></div>
   <div class="middle"></div>
   <div class="right"></div>
 </div>
.middle {
	width: 200px;
    flex: 0 1 20%;
    background: yellow;
}

问题:求left middle right的实际长度是多少?

解析:middle的flex属性设置为0 1 20%,之前两列情况最后有总结到,flex-basis有值的时候,设置了width也只是干扰条件不参与进来,middle初始长度就是父元素长度600 * 20% = 120px,,完整计算如下:

// 父容器 width: 600px,left初始长度500px,right初始长度为400px
let leftBasisWid = 500px; // left初始因为为flex-basis为500px
let rightBasisWid = 400px; // right初始因为为flex-basis为400px
let middleBasisWid = 120px; // middle初始因为为flex-basis为20%,所以为600px * 20% = 120px
let overSpace = (500px + 400px + 120px) - 600px = 420px; // 剩余空间不足,溢出空间为420px
let totalWeight = 2 * 500 + 1 * 400 + 1 * 120 = 1520; // 总权重值(2 1 1为left right middle的flex-shrink值)
let leftRatio = 2 * 500 / totalWeight; // left的收缩比
let rightRatio = 1 * 400 / totalWeight; // right的收缩比
let middleRatio = 1 * 120 / totalWeight; // middle的收缩比
let leftShrinkWid = overSpace * leftRatio  = 276.31px; // left的缩小比例长度
let rightShrinkWid = overSpace * rightRatio  = 110.52px; // right的缩小比例长度
let middleShrinkWid = overSpace * middleRatio  = 33.16px; // middle的缩小比例长度
let widthLeft = leftBasisWid - leftShrinkWid = 223.96px; // left实际长度
let widthRight = rightBasisWid - rightShrinkWid = 289.48px; // right实际长度
let widthMiddle = middleBasisWid - middleShrinkWid = 86.84px; // middle实际长度

在这里插入图片描述

结语

本文主要从题目场景入手,进行解析,让大家动手中理解。题目变化当然是灵活的,但其实你只需要搞清楚flex属性设置的值的意思(尤其是flex-basis的值),以及知道空间到底是剩余(放大)还是溢出(收缩),按照上面的思路,不管几列都可以算清楚,从而得心应手理解透彻,也有助于写页面时更好的把控页面布局。

嗯,大概自己的总结就先到这吧,后续迷惑点有了再写喽…😁

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Flex弹性布局,可以通过以下方式实现上下的排列: 1. 使用flex容器:将要显示的内容包裹在一个具有flex属性的父容器。设置父容器的display为flex,这样子元素就可以按照弹性布局进行排列。 2. 上下排列方式:使用flex-direction属性来定义子元素的排列方向。要实现上下的排列,可以将flex-direction设置为column。 3. 上部元素:为上部元素设置相应的flex属性,可以通过设置flex-grow、flex-shrink和flex-basis来控制元素的伸缩性。比如设置flex: 1,表示该元素会根据可用空间进行扩展或收缩。 4. 部元素:为部元素设置相应的flex属性,也可以使用align-self属性来控制元素在交叉轴上的对齐方式。比如设置align-self: center,表示元素在交叉轴上居对齐。 5. 下部元素:同样地,为下部元素设置相应的flex属性,并根据需求调整伸缩性和对齐方式。 以下是一个示例代码: ```html <div class="flex-container"> <div class="item">上部</div> <div class="item">部</div> <div class="item">下部</div> </div> ``` ```css .flex-container { display: flex; flex-direction: column; height: 100vh; /* 设置父容器的高度,以便撑开页面 */ } .item { flex: 1; /* 上部和下部元素会平分剩余的空间 */ display: flex; align-items: center; justify-content: center; } ``` 通过以上方式,你可以实现一个基本的上下排列的Flex弹性布局。根据实际需求可以进一步调整样式和布局。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值