一篇文章带你掌握Flex布局的所有用法(下)

简介: 一篇文章带你掌握Flex布局的所有用法(下)

Flex 项目大小的计算



首先看一下 flex-grow 的计算方式


flex-grow


面试中经常问到: 为什么 flex 设置为 1 的时候,Flex 项目就会均分 Flex 容器? 其实 Flex 项目设置为 1 不一定会均分容器(后面会解释),这里我们先看下均分的情况是如何发生的

同样的我们先举个例子

<div class="container">
  <div class="item">Xiaoyue</div>
  <div class="item">June</div>
  <div class="item">Alice</div>
  <div class="item">Youhu</div>
  <div class="item">Liehuhu</div>
</div>


.container {
  display: flex;
  width: 800px;
}
.item {
  flex: 1;
  font-size: 30px;
}

flex 容器总宽度为 800px,flex 项目设置为flex:1,此时页面上显示

image.png

我们可以看到每个项目的宽度为 800/5=160,下面来解释一下为什么会均分:

首先

.item {
  flex: 1;
  /* 相当于 */
  flex-grow: 1;
  flex-shrink: 1;
  flex-basis: 0;
}

因为flex-basis为 0,所有 Flex 项目扩展系数都是 1,所以它们分到的剩余空间都是一样的。下面看一下是如何计算出最终项目大小的


这里先给出一个公式:

Flex项目弹性量 = (Flex容器剩余空间/所有flex-grow总和)*当前Flex项目的flex-grow

其中Flex项目弹性量指的是分配给 Flex 项目多少的剩余空间,所以 Flex 项目的最终宽度为

flex-basis+Flex项目弹性量

根据这个公式,上面的均分也就很好理解了,因为所有的flex-basis为 0,所以剩余空间就是 800px,每个 Flex 项目的弹性量也就是(800/1+1+1+1+1)*1=160,那么最终宽度也就是160+0=160

刚刚说过 flex 设置为 1 时 Flex 项目并不一定会被均分,下面就来介绍一下这种情况,我们修改一下示例中的 html,将第一个 item 中换成一个长单词

<div class="container">
  <div class="item">Xiaoyueyueyue</div>
  <div class="item">June</div>
  <div class="item">Alice</div>
  <div class="item">Youhu</div>
  <div class="item">Liehu</div>
</div>

此时会发现 Flex 容器并没有被均分

image.png


因为计算出的灵活性 160px 小于第一个 Flex 项目的min-content(217.16px),此时浏览器会采用 Flex 项目的min-content作为最终宽度,而后面的 Flex 项目会在第一个 Flex 项目计算完毕后再进行同样的计算

我们修改一下 flex,给它设置一个 flex-basis,看下它计算之后的情况

.item {
  text-align: center;
  flex: 1 100px;
}

因为每个项目的flex-basis都是 100px,Flex 容器剩余空间800-500=300px,所以弹性量就是(300/5)*1=60px,最终宽度理论应该为100+60=160px,同样的因为第一个 Flex 项目的min-content为 217.16px,所以第一个 Flex 项目宽度被设置为 217.16px,最终表现和上面一样

image.png

我们再来看一下为什么第 2,3,4,5 个 Flex 项目宽度为什么是 145.71px

image.png

当浏览器计算完第一个 Flex 项目为 217.16px 后,此时的剩余空间为800-217.16-100*4=182.84,第 2 个 Flex 项目弹性量(182.84/1+1+1+1)*1=45.71,所以最终宽度为100+45.71=145.71px,同样的后面的 Flex 项目计算方式是一样的,但是如果后面再遇到长单词,假如第五个是长单词,那么不足空间将会发生变化,浏览器会将第五个 Flex 项目宽度计算完毕后再回头进行一轮计算,具体情况这里不再展开


所以说想要均分 Flex 容器 flex 设置为 1 并不能用在所有场景中,其实当 Flex 项目中有固定宽度元素也会出现这种情况,比如一张图片等,当然如果你想要解决这个问题其实也很简单,将 Flex 项目的min-width设置为 0 即可

.item {
  flex: 1 100px;
  min-width: 0;
}

image.png


flex-grow 为小数


flex-grow 的值不仅可以为正整数,还可以为小数,当为小数时也分为两种情况:所有 Flex 项目的 flex-grow 之和小于等于 1 和大于 1,我们先看小于等于 1 的情况,将例子的改成

<div class="container">
  <div class="item">Acc</div>
  <div class="item">Bc</div>
  <div class="item">C</div>
  <div class="item">DDD</div>
  <div class="item">E</div>
</div>
.item:nth-of-type(1) {
  flex-grow: 0.1;
}
.item:nth-of-type(2) {
  flex-grow: 0.2;
}
.item:nth-of-type(3) {
  flex-grow: 0.2;
}
.item:nth-of-type(4) {
  flex-grow: 0.1;
}
.item:nth-of-type(5) {
  flex-grow: 0.1;
}

效果如图

image.png

我们可以发现项目并没有占满容器,它的每个项目的弹性量计算方式为

Flex项目弹性量=Flex容器剩余空间*当前Flex项目的flex-grow

相应的每个项目的实际宽度也就是flex-basis+弹性量,首先先不设置 flex-grow,我们可以看到每个项目的 flex-basis 分别为: 51.2 , 33.88 , 20.08 , 68.56 , 16.5

image.png

所以我们可以计算出 Flex 容器的剩余空间为800-51.2 -33.88 - 20.08 - 68.56 - 16.5=609.78,这样我们就可以算出每个项目的实际尺寸为

A: 实际宽度 = 51.2 + 609.78*0.1 = 112.178

B: 实际宽度 = 33.88 + 609.78*0.2 = 155.836

...

下面看下 flex-grow 之和大于 1 的情况,将例子中的 css 改为

.item:nth-of-type(1) {
  flex-grow: 0.1;
}
.item:nth-of-type(2) {
  flex-grow: 0.2;
}
.item:nth-of-type(3) {
  flex-grow: 0.3;
}
.item:nth-of-type(4) {
  flex-grow: 0.4;
}
.item:nth-of-type(5) {
  flex-grow: 0.5;
}

此时的效果为

image.png

可以看出 Flex 项目是占满容器的,它的计算方式其实和 flex-grow 为正整数时一样

Flex项目弹性量 = (Flex容器剩余空间/所有flex-grow总和)*当前Flex项目的flex-grow

所以我们可以得出一个结论: Flex 项目的 flex-grow 之和小于 1,Flex 项目不会占满 Flex 容器


flex-shrink


flex-shrink 其实和 flex-grow 基本一样,就是扩展变成了收缩,flex-grow 是项目比例增加容器剩余空间,而 flex-shrink 则是比例减去容器不足空间

修改一下我们的例子:

.item {
  flex-basis: 200px;
  /* 相当于 */
  flex-shrink: 1;
  flex-grow: 0;
  flex-basis: 200px;
}

此时项目的总宽度200*5=1000px已经大于容器总宽度800px,此时计算第一个项目的不足空间就是800-200*5=-200px,第二个项目的不足空间则是800-第一个项目实际宽度-200*4,依次类推


最终计算公式其实和 flex-grow 计算差不多

Flex项目弹性量 = (Flex容器不足空间/所有flex-shrink总和)*当前Flex项目的flex-shrink


只不过,所以上面例子每个项目可以计算出实际宽度为

第一个 Flex 项目: 200+((800-200x5)/5)*1 = 160px

第二个 Flex 项目: 200+((800-160-200x4)/4)*1 = 160px

第三个 Flex 项目: 200+((800-160-160-200x3)/3)*1 = 160px

第四个 Flex 项目: 200+((800-160-160-160-200x2)/2)*1 = 160px

第五个 Flex 项目: 200+((800-160-160-160-160-200x1)/1)*1 = 160px

如果 Flex 项目的min-content大于flex-basis,那么最终的实际宽度将会取该项目的min-content,比如改一下例子,将第一个 Flex 项目改成长单词


<div class="container">
  <div class="item">XiaoyueXiaoyue</div>
  <div class="item">June</div>
  <div class="item">Alice</div>
  <div class="item">Youhu</div>
  <div class="item">Liehu</div>
</div>

image.png

可以看出浏览器最终采用的是第一个 Flex 项目的min-content作为实际宽度,相应的后面 Flex 项目的宽度会等前一个 Flex 项目计算完毕后在进行计算

比如第二个 Flex 项目宽度= 200+((800-228.75-200x4)/4)*1 = 142.81px


flex-shrink 为小数


同样的 flex-shrink 也会出现小数的情况,也分为 Flex 项目的 flex-shrink 之和小于等于 1 和大于 1 两种情况,如果大于 1 和上面的计算方式一样,所以我们只看小于 1 的情况,将我们的例子改为


.item {
  flex-basis: 200px;
  flex-shrink: 0.1;
}

效果为

image.png


此时我们会发现 Flex 项目溢出了容器,所以我们便可以得出一个结论:Flex 项目的 flex-shrink 之和小于 1,Flex 项目会溢出 Flex 容器


下面看一下它的计算公式

Flex项目弹性量=Flex容器不足空间*当前Flex项目的flex-shrink

Flex项目实际宽度=flex-basis + Flex项目弹性量

比如上面例子的每个 Flex 项目计算结果为

第一个 Flex 项目宽度 = 200+(800-200x5)x0.1=180px,但是由于它本身的min-content为 228.75,所以最终宽度为 228.75

第二个 Flex 项目宽度 =200-(800-228.75-200x4)x0.1=117.125

第三个 Flex 项目宽度...


Flex 的对齐方式



Flex 中关于对齐方式的属性有很多,其主要分为两种,一是主轴对齐方式:justify-*,二是交叉轴对齐方式:align-*

首先改一下我们的例子,将容器设置为宽高为 500x400 的容器(部分属性省略)

<div class="container">
  <div class="item">A</div>
  <div class="item">B</div>
  <div class="item">C</div>
</div>
.container {
  display: flex;
  width: 500px;
  height: 400px;
}
.item {
  width: 100px;
  height: 40px;
}

image.png


主轴对齐属性



这里以横向为主轴,纵向为交叉轴


justify-content


justify-content的值可以为:

  • flex-start 默认值,主轴起点对齐

image.png

  • flex-end 主轴终点对齐

image.png

  • left 默认情况下和 flex-start 一致
  • right 默认情况下和 flex-end 一致
  • center 主轴居中对齐

image.png

  • space-between 主轴两端对齐,并且 Flex 项目间距相等

image.png

  • space-around 项目左右周围空间相等

image.png

  • space-evenly 任何两个项目之间的间距以及边缘的空间相等

image.png


交叉轴对齐方式


align-content

align-content 属性控制整个 Flex 项目在 Flex 容器中交叉轴的对齐方式

**注意设置 align-content 属性时候必须将 flex-wrap 设置成 wrap 或者 wrap-reverse。**它可以取得值为

  • stretch 默认值,当我们 Flex 元素不设置高度的时候,默认是拉伸的

比如将 Flex 元素宽度去掉


.item {
  width: 100px;
}

image.png

  • flex-start 位于容器开头,这个和 flex-direction:属性有关,默认在顶部

image.png

  • flex-end 位于容器结尾

image.png

  • center 元素居中对齐

image.png

  • space-between 交叉轴上下对齐,并且 Flex 项目上下间距相等

此时我们改下例子中 Flex 项目的宽度使其换行,因为如果 Flex 项目只有一行,那么 space-between 与 flex-start 表现一致

.item {
  width: 300px;
}

image.png

  • space-around 项目上下周围空间相等

image.png

  • space-evenly 任何两个项目之间的上下间距以及边缘的空间相等

image.png


align-items


align-items 属性定义 flex 子项在 flex 容器的当前行的交叉轴方向上的对齐方式。它与 align-content 有相似的地方,它的取值有

  • stretch 默认值,当我们 Flex 元素不设置高度的时候,默认是拉伸的
  • center 元素位于容器的中心,每个当前行在图中已经框起来

image.png

  • flex-start 位于容器开头
  • flex-end 位于容器结尾
  • baseline 位于容器的基线上

比如给 A 项目一个 padding-top

.item:nth-of-type(1) {
  padding-top: 50px;
}

没设置 baseline 的表现

image.png

设置 baseline 之后

image.png

通过上面的例子我们可以发现,如果想要整个 Flex 项目垂直对齐,在只有一行的情况下,align-items 和 align-content 设置为 center 都可以做到,但是如果出现多行的情况下 align-items 就不再适用了


align-self


上面都是给 Flex 容器设置的属性,但是如果想要控制单个 Flex 项目的对齐方式该怎么办呢?

其实 Flex 布局中已经考虑到了这个问题,于是就有个 align-self 属性来控制单个 Flex 项目在 Flex 容器侧交叉轴的对齐方式。

align-self 和 align-items 属性值几乎是一致的,比如我们将整个 Flex 项目设置为 center,第二个 Flex 项目设置为 flex-start

.container {
  display: flex;
  width: 500px;
  height: 400px;
  align-items: center;
}
.item {
  width: 100px;
  height: 40px;
}
.item:nth-of-type(2) {
  align-self: flex-start;
}

image.png


注意,除了以上提到的属性的属性值,还可以设置为 CSS 的关键词如 inherit 、initial 等


交叉轴与主轴简写



place-content


place-contentjustify-contentalign-content 的简写形式,可以取一个值和两个值,如果设置一个值那么 justify-contentalign-content 都为这个值,如果是两个值,第一个值为 align-content,第二个则是 justify-content

到这里关于Flex布局基本已经介绍完了,肯定会有些细枝末节没有考虑到,这可能就需要我们在平时工作和学习中去发现了


相关文章
|
2天前
解决flex布局最后一行(左靠齐)
解决flex布局最后一行(左靠齐)
|
9月前
|
前端开发 容器
|
9月前
|
前端开发 小程序 容器
|
9月前
|
容器
Flex布局是什么?
Flex布局是什么?
|
9月前
|
开发者 容器
Flex基础布局
Flex基础布局
|
11月前
|
前端开发 容器
一篇文章带你掌握Flex布局的所有用法(上)
一篇文章带你掌握Flex布局的所有用法(上)
59 0
|
11月前
Flex布局实战详解(上)
Flex布局实战详解(上)
103 0
|
11月前
Flex布局实战详解(下)
Flex布局实战详解(下)
63 0
|
12月前
|
容器
Flex布局学习
Flex布局学习