likes
comments
collection
share

可以了解一些flex不一样的知识

作者站长头像
站长
· 阅读数 14

前言

相信flex布局大家都知道,都学习过,已经都已经在使用了。在日常使用过程中其实基本的知识足以应付了。

本篇文章讨论的是一个较为深入的知识,可能更多的是偏向于理论知识上,对此不了解可能也不会影响到大家的实际使用。但是了解过后,可能对日后遇到的一些问题避免陷入钻牛角尖的地步。

大家都知道flex是能够自动延申或挤压,但是有人好奇它是怎么计算的吗?对部分介绍的属性是否清楚了解其是怎么生效的。本篇文章能带给你不一样的角度去重新认识一下flex,带给你一个全新的认识体验。

原创文章,经过个人实践测试总结出来的,欢迎大家多多支持

基础认识

因为本篇文章重点不在讲述flex的基础知识,所以若你未了解过,请先阅读以下文章

基础的知识可阅读以下资料:

加深认识

这里我们把父元素设置display: flex;称之为【flex容器】, 其子元素(不含子孙元素)我们称之为【flex项目】,以下所有说明都是以flow-direction: row为例子,即水平方向为主轴的情况为例子

flex-basis

该属性是在任何空间分配发生之前初始化 flex项目 的尺寸。默认值是auto ,如果flex项目设置了的width,则flex-basis即等于这个width的实际值对应的px值,如果没有设置,则即为flex项目自身大小,实际上flex项目的是max-content

当然该属性我们可以设定具体大小值。

该属性有什么作用呢?

  • 该属性才是用来决定flex项目尺寸的,而不是width,在flex-basis: auto;情况下width只是间接赋默认值给flex-basis,最终还是flex-basis决定了flex项目的尺寸。
    • 因此在没有多余空间或不足空间的情况下,设置该值相当于设置了该flex项目的最终宽度
  • 用于判断主轴上是否有多余空间或不足空间
  • 当有多余空间允许扩展flex项目或不足空间时挤压flex项目,用于计算flex项目扩展多少或挤压多少

判断是否有多余空间或不足

是根据flex项目的flex-basis之和决定的,如果在主轴空间内还存在其他尺寸因素,如flex容器的padding,border,或flex项目的margin,或box-sizing:content情况下flex项目的padding,border等设定好的边距样式,那么也要加上这些值之后判断,如果和大于flex容器宽度,则存在不足空间,如果小于flex容器宽度,则存在多余空间。

计算扩展或挤压值

如果存在多余空间flex可进行延申 或 不足空间进行挤压,也是根据flex-basis的值来进行计算的。接下来我们深入了解下是如何利用它进行计算的。

首先flex项目肯定需要设置flex-growflex-shrink才能发生尺寸变化,而flex-shrink默认值是1,默认会在不足空间情况下发生挤压。flex-grow默认值是0,不会发生扩展。

接下来要知晓flex-growflex-shrink是基于什么公式进行计算实际变动量的。

以flex容器(设置了display: flex;的容器)总宽度500px为例子,底下有两个子元素,子元素A设置宽度width: 100px;flex-grow: 1;,子元素B设置宽度width: 200px;flex-grow: 2;

所以在两个子元素宽度和100 + 200 < 500的情况下,是有多余空间进行扩充的,有200px(500-100-200)的多余空间。 根据两个子元素设置的flex-grow的比例可以看到,A元素与B元素的可扩充比例为1:2

假设A元素的扩充值为x,B元素的扩充值为y,则根据扩充比例得出 x/y = 1/2

而他们的扩充值无非就是瓜分多余的200px空间,所以就是 x + y = 200, 因此只要解出这个二元一次方程组就能算出x,y的值。

x/y = 1/2
x + y = 200

然后最终A元素的宽度为100 + x , B元素的宽度为200+y。

同理,对于可挤压的情况,也是根据flex-shrink知道挤压比例,然后结合不足的空间部分,算出x 和 y, 得到最终值。

上面的例子中,都是直接指定子元素的width,但是如果也设置了flex-basis,则就是用flex-basis设定的值作为该项目的基准进行计算的,这个属性就是用来指定在面对可扩充或挤压情况下计算的基准,正因为它默认值是元素自身宽度,所以在没设置它的情况下,看似是拿width来进行计算,但是实际上还是用flex-basis计算。

ps: 上面的例子只是恰好是二元一次方程组,因为只有两个项目,假设项目多,就不只是一个二元一次方程组了

计算出来的值是理想值,当其中某个flex项目压缩到不能再压缩了,则整体的压缩到此为止,具体下节说明。

flex-shrink

flex-shrink默认值为1,意味着空间不足时会进行压缩项目,但是压缩到什么程度为止呢?压缩到项目自身的最小宽度/高度,即不能再小的地步,注意是最小宽度,而不是设置的宽度,就算设置了width也是可能继续挤压的。这个不是一个可以量化的标准,什么叫最小的地步,要视项目自身的样式设置以及内容而定。

可以罗列下几种常见的情况(以水平方向flow-direction: row为例说明):

  1. 项目设置了最小宽度min-width,则压缩到指定的最小宽度为止
  2. 项目没有设置最小宽度,则压缩到自身内容撑开的宽度为止

基于第二种情况,又可以展开分为几种场景说明:

  1. 项目设置了word-break: break-all; 意味着原本在不换行的情况下由内容撑开了项目是最小宽度,现在却因为能换行了,所以这个最小宽度就随之变为换行后的由内容撑开的宽度了。
  2. 项目设置了overflow: auto;overflow: hidden;overflow: scroll;等情况,由于允许出现滚动条查看内容,意味着项目内容自身可以无限小,趋向0,基本看不到啥内容了
  3. 项目设置了paddingmargin,不论怎么压缩,始终是保留着设定的paddingmargin,压缩的只是内容自身而已。

flex-wrap

设置了flex-wrap: wrap允许换行。换行后我们可以从理解上认为每一行都是一个flex容器,或者理解成每一行都存在一条主轴和交叉轴。

还是以flex-direction:row;为例子说明

现在我好奇的是,换行后,存在多主轴时,想知道每个主轴所占的高度是多少。这个高度是怎么计算的?

在不设置align-content时,默认是stretch,轴线占满整个交叉轴,即高度为交叉轴的高度。如果设置了其他值,则每行的高度是按照行内项目自身内容最大高度,这个不复杂,就跟只有一根主轴的情况一样(flex-wrap: nowrap)。

复杂的是多主轴且align-content: stretch;情况下,每行高度是怎么计算的。

ps:align-content属性在不设置flex-wrap:wrap 或 wrap-reverse的情况下使用时不生效的。设置了之后就算里面的实际内容没有换行也是会生效的。

计算原理概述:

首先当知道要换成多少行后,将flex容器的高度按照行数平均分,这是每行的初始高度,这里是假定每行每个项目都是一行内容的情况下的高度,接着根据每行的高度是由项目的实际内容在这个初始高度上增加超出一行内容的高度,取最大的值作为这一行的高度。因为有的行的高度变大了,自然其他行就要相应进行挤压。挤压的变动情况就跟flex-shrink类似。

例子解析:

上面文字说明有点迷糊,下面还是以实际例子说明。

demo

flex容器元素300px,里面的项目将会被换行,结果成三行展示,所以每行(一行一个主轴)的高度理应为 300px / 3 = 100px,由于第一行中的第二个项目是有两行内容,每行内容所占高度为21px,所以理应flex容器的第一行高度应该为100px + 21 = 121px,但是因为flex容器高度不够,就需要挤压每行的高度,情况就跟flex-shrink的计算一样,这里相当于每行默认设置了一个flex-shrink: 1,因此按照上一节说的原理得出计算公式:

x + 2y = 21
x/y = 1

计算的x = y = 7

所以flex容器第一行最终高度为 121px - 7 = 114px,第二第三行为100px - 7 = 93px

如果上述通过工时理解的有些人可能觉得不够直接,太公式化了。那么我们换种理解思路,我觉得更方便点:

原本flex容器高度300px,平均分三行后每行理应占据100px的高度,由于第一行里有项目的内容是超过一行的,超出的高度为21px,那么原本300px的平均分结果不适用,因此我们把flex容器的高度假设为 300px -21px = 279px 后再平均分 279px / 3 = 93px,在这个结果上第一行就补回假设掉的21px,即 93px + 21px = 114px

align-self

这个比较简单,没啥特别好说的,特意写在这里是因为自己用的比较少,放在这里提醒一下,因为这个实在属性实在好用。

这个属性是单独指明某个flex项目在交叉轴的排列方式。我们知道flex容器可以通过align-items来设置所有flex项目在交叉轴的排列方式,而这个属性是直接写在flex项目里的,单独指出该flex项目在交查的排列方式。

什么情况下最常用到呢?我们知道align-items默认值是stretch,好处是高度能充斥满整个交叉轴,特别是要求所有flex项目的高度都跟最高的保持一致,或者换个说法就是随着最高的flex项目高度而同等撑高。如图:

可以了解一些flex不一样的知识

这里灰色底部分就是很好利用了stretch的特性,让整个div充斥到一行的最大高度,通过背景颜色可以看出。

而白色底部分,其实设置了align-self: center,让内容垂直居中了,实际上它的高度只有文本内容自身高度,但是没关系,因为这里都是白色底,看不出,视觉上让人觉得是垂直居中就好了。

大家感兴趣可以试下实现这个效果。

align-items

只有一点值得特别提一下的,当flex-row: column时,align-items:stretch不会把flex 项目的实际宽度拉伸到充斥整个交叉轴,但位置的排列还是按照整个交叉轴所占位置来排列。

即当你通过开发者工具审查元素时看到,flex项目的宽度还是自身内容的宽度,但是排列的位置例如从左到右排列时,第二个flex元素开始排列的位置是从前一个flex项目的交叉轴长度的末尾点开始算起。

flex-row: row时就是能被拉伸到交叉轴的高度。

总结

关于flex的介绍的文章很多,千篇一律。但是我相信阅读了我这篇能够给大家带来不一样的感受,所以才写到掘金上来。(因为我现在本来也很少写这类)。

如有更多问题,欢迎一起讨论学习。

本文正在参加「金石计划」

转载自:https://juejin.cn/post/7223695339328880698
评论
请登录