关于前端:从误解-flex-1-到理解-flexbox

44次阅读

共计 5482 个字符,预计需要花费 14 分钟才能阅读完成。

背景

咱们常常在某些业务场景中,须要实现子元素均等占用父元素空间的成果。到目前为止,我应用最多的就是用 flex: 1 来实现。直到有一天我忽然想应用 flex-grow: 1 来达到雷同的成果,然而浏览器却给了我不一样的体现,我才发现我疏忽了 残余空间free space)这个关键词。始终以来,我是以 flex container 的宽度为根底来思考空间调配的问题,简略得将 flex: 1flex-grow: 1 划上了等号。

本文是重新学习了 flexbox 之后做的总结,次要围绕 flexflex-basisflex-grow 以及 flex-shrink 这 4 个属性。

在 Firefox 审查 flexbox 布局的节点能够看到一些尺寸数据,然而 Chrome 如同并不能,所以文中的代码都会在 Firefox 中审查,我的 Firefox 版本是 65.0.2。

flexbox 基本概念

对于一些基础知识,其余文章曾经有具体的阐明,本文就只是简略表述一下。

  1. 首先,设置了 display: flex 的元素会成为一个 flex container,并创立一个 FFC(Flex Formatting Context),而该元素自身则会体现为一个 块级元素 ,相应的,设置了 inline-flex 的元素则体现为 内联元素
  2. flex container 外部的元素会成为 flex item,包含外部的纯文本(会被包裹一个匿名块级盒子)。相对定位元素因为不会参加到 flex 布局中来,所以不会成为一个 flex item
  3. 最初,在进行 flex layout 时,flex 会失效,使 flex item 齐全填充至 flex container 的可用空间,或者膨胀 flex item 以阻止溢出。当所有的 flex item 确定了尺寸之后,就会依据 justify-contentalign-self 等属性进行排列和布局。

flex-basis

flex-basis 会代替 flex item 在主轴(main axis)方向上的尺寸属性(width/height),并在 调配残余空间 (_free space_) 之前 初始化 flex item 的主轴尺寸。

承受的值与 width 或者 height 雷同,比方数值、百分比、automin-content 以及 max-content,另外还有 content

auto

被指定为 auto 时,会取以后 flex item 主轴尺寸属性(width/height)的值,如果取到的值是 auto 时,则会应用 content,也就是依据 flex item 的内容大小来确定。比方以下构造:

<div style="display: flex; width: 200px; border: 1px dotted #333;">

  <div id="first" style="background: #eee; width: 80px; flex-basis: auto;">
    short text

  </div>

  <div id="second" style="background: #ccc; flex-basis: auto;">
    very looooooooong text

  </div>
</div>

应用 Firefox(反对 content,然而 min-contentmax-content 是有效值)审查节点的时候能够看到:
<img width=”391″ alt=” 根底尺寸 ” src=”https://user-images.githubusercontent.com/13151172/91567558-be38e080-e977-11ea-83f5-2a6af5a3be01.png”>
<img width=”391″ alt=” 内容尺寸 ” src=”https://user-images.githubusercontent.com/13151172/91567585-bf6a0d80-e977-11ea-9cae-b18eaa288c33.png”>
因为设置了 width: 80px,所以 div#first 的根底尺寸是 80px,而 div#second 的宽度是 auto,所以它的根底尺寸就基于它的内容失去,即内容尺寸。

content(兼容性不好)


被指定为 content 时,是依据 flex item 的内容大小来确定尺寸的。相当于应用了 width: max-content。Chrome 是不反对该值的,Firefox 能够应用该值。

flex-grow

简略讲,flex-grow 是指以后 flex item 能够从 flex container 的残余空间(positive free space)里调配到多少比例。

这里有一个关键词是positive free space,而我之前误会成了 flex container 的整个 content box

例如 flex-grow: 1 就是指心愿调配到 100%positive free spaceflex-grow: 0.5 就是指 50%,以此类推。所以,当所有的 flex-grow 总和小于 1 时,这些 flex items 也就没有调配到 100% 的 positive free space,就会有空间被剩下;当所有的 flex-grow 总和大于 1 时,就会以 100% 为根底从新计算比例,毕竟不会有超过 100% 的空间能够调配。

flex-shrink

MDN 中的定义:

flex-shrink 属性指定了 flex 元素的膨胀规定。flex 元素仅在默认宽度之和大于容器的时候才会产生膨胀,其膨胀的大小是根据 flex-shrink 的值。

能够用 negative free space 来示意溢出的空间。与 flex-grow 不同的是,如果指定 flex-shrink: 1,不能简略的了解为这个 flex item 心愿调配到 100% 的 negative free space。这里的 1 相当于一个权重,具体的计算过程会在如何计算弹性中形容。

在膨胀规定中,有一个概念是 content-based minimum size,直译过去是 基于内容的最小尺寸 。它限度了 flex item 能够膨胀的水平,不会让 flex item 膨胀到更小的尺寸。它的值可能是一个确定的 主轴(main axis)尺寸属性值(width/height),也可能是 min-content。这个概念会在如何计算弹性中应用到。

flex

flex: 0 1 auto 是它的初始值。也就是说 flex item 在默认状态下,能够在主轴维度上放大但不能拉伸,并且依据 width/height 来确定其大小。

而被我误会为等价于 flex-grow: 1flex: 1,残缺的值是 flex: 1 1 0flex: <positive-number> 1 0)。

如何计算弹性

<div style="display: flex; width: 200px; border: 1px dotted #333;">
  <div id="first" style="background: #eee;">
    short text
  </div>
  <div id="second" style="background: #ccc; width: 280px;">
    very looooooooong text
  </div>
</div>

以上述代码为例:

步骤一

确定主轴(main axis)的可用空间(available space),也就是 flex containercontent box,可能是一个确定的尺寸,也可能须要计算得出。

例子中的可用空间就是 200px。

步骤二

依据 flex-basis 确定每一个 flex item 根底尺寸(flex base size)


因为 div#firstflex-basiswidth 都为 auto,所以他的根底尺寸就是它的内容尺寸,通过 Firefox 审查节点能够看到它的内容尺寸是 59.93px。而 div#second 因为设置了 width: 280px,所以 280px 就是它的根底尺寸。
另外,在这一步骤中,最大最小束缚(这个例子是 min-wdithmax-width)会被疏忽。如果给 div#first 一个 min-width: 100px,它的根底尺寸仍然是 59.93px。至于这些束缚何时失效,能够在前面的步骤看到。

步骤三

计算 flex item 的主轴尺寸(main size)总和,确定应用 flex-grow 还是 flex-shrink


例子中,能够失去总和是 339.93px,超过了 flex container 的尺寸,所以能够确定 flex-shrink 失效。

步骤四

__确定 positive free space 或者 negative free space 的大小__。

首先,须要计算例子中 flex-shrink 的总和,失去值为 2。因为大于 1,所以 negative free space 的值就是 339.93px – 200px = 139.93px。

步骤五

为每个 flex item 调配 free space,确定批改后的尺寸。

因为在这个例子中失效的是 flex-shrink 属性,所以每个 flex item 的最终大小是根底尺寸减去它所调配到的 negative free space。那么,每一个 flex item 应该被调配到多少呢?

<img width=”818″ alt=” 公式 ” src=”https://user-images.githubusercontent.com/13151172/91580974-75d1f080-e980-11ea-9821-1d5ecc031f1f.png”>

在这个公式里,能够看到根底尺寸与 flex-shrink 的值做了相乘,也就是上文 flex-shrink 中说到的权重。能够简略套用这个公式:

  • div#first : (339.93 – 200) * 59.93 / (59.93 + 280) = 24.67px

  • div#second: (339.93 – 200) * 280 / (59.93 + 280) = 115.26px


所以最初 div#first 的宽度是 35.27px,div#second 是 164.73px。在这个例子中,以上就是最终尺寸了,能够在 Firefox 审查节点看到这个后果。

然而,如果将 div#second 的宽度调整到 1000px,就会有接下来的这一步,咱们能够看到 flex-shrink 中提到的 content-based minimum size 会起到限度作用,步骤 2 中的最大最小束缚也会失效。

步骤六

依据 min/max-width(min/max-height) 或者 content-based minimum size 修改 flex item 的尺寸。

咱们把 div#secondwidth 设置为 1000px,而后套用下面的公式:

  • div#first : (1059.93 – 200) * 59.93 / (59.93 + 1000) = 48.62px

  • div#second: (1059.93 – 200) * 1000 / (59.93 + 1000) = 811.31px


如果没有把这一步骤写进去,兴许你会认为 div#first 的最终尺寸就是 59.93 – 48.62,div#second 是 1000 – 811.31。咱们能够在 Firefox 审查一下:

<img width=”350″ alt=” 审查后果 ” src=”https://user-images.githubusercontent.com/13151172/91581319-e37e1c80-e980-11ea-9027-bb0cedd7419c.png”>

div#first 的内容尺寸以及弹性确实和咱们料想的一样,而最终尺寸却是 31.97px。在这里就是 content-based minimum size 失效了,它应用 div#firstmin-content 作为了它的值。

如果咱们设置了一个确定的 width,content-based minimum size 其实会取 widthmin-content 之间的最小值,比方 width: 10px,那么 div#first 的最终尺寸就是 10px。

__我就是心愿 div#first 的最终尺寸是 59.93 – 48.62 = 11.31px__,这该如何做呢?为 div#first 加上 min-width: 5px,这样一来它的最终尺寸就成了 11.31px。

如果 flex-grow 失效,如何计算

以这段代码为例:

<div style="display: flex; width: 300px; border: 1px dotted #333;">
  <div style="background: #eee; flex-grow: 2;">
    short text
  </div>
  <div style="background: #ccc; flex-grow: 1;">
    very looooooooong text
  </div>
</div>
  1. 首先,主轴的可用空间是 300px。
  2. 每一个 flex item 的根底尺寸是它们的内容尺寸,别离是 59.93px 和 152.82px。
  3. flex item 的主轴尺寸总和是 212.75px,所以 flex-grow 失效。
  4. 确定 positive free space 的大小是 87.25px。
  5. 计算 flex item 调配到的 positive free space,别离是 87.25 2 / (2 + 1) = 58.17px 和 87.25 1 / (2 + 1) = 29.08px。确定最终尺寸别离是 118.1px 和 181.9px。

最初

本文做的总结基本上能够笼罩我目前碰到的业务场景了,将来兴许会碰到更多的场景来调整我对 flexbox 的了解。对于 flex layout 的算法,W3C 有十分具体且简单的介绍,本文做了肯定的调整和简化。如果想要理解更多,能够去 W3C 看看一些介绍。

正文完
 0