美文网首页
从 chrome flexbox devtool 探究 flex

从 chrome flexbox devtool 探究 flex

作者: HoPGoldy | 来源:发表于2021-06-03 15:06 被阅读0次

前言

自从 chrome 90 更新后,devtool 专门为 flexbox 添加了一个调试工具,只需要点击 display: flex; 后的小按钮就可以打开一个小面板,可以直接添加对应的 flex 样式:

但是仅仅如此么?当然不是,这个更新最大的改动,就是为页面中的 flex 布局添加了专属的显示效果。不知道你在开发时有没有注意到下图这样的紫色斜线条纹:

这些紫色斜条纹区域代表了 由于 flex 布局而产生的间隙,这些区域里不会存在 flex 子项的。除此之外,还有一个下面这样的效果可能会让人有点摸不着头脑:

一块紫色区域带个向外的箭头 一块紫色区域带个向内的箭头

这种代表着 主轴 flex 子项的缩放效果,众所周知,flex 元素上可以通过 flex-growflex-shrink指定子项在存在剩余空间 / 空间不足的情况下如何进行缩放,而上图中 紫色虚线区域代表了该子项原本的大小,箭头表示经过 flex 缩放后的元素实际大小。

然而,并不是所有的 flex 子项都会显示一个对应的紫色虚线块。例如下面这个例子:

<style>
    .flex-box {
        display: flex;
        width: 300px;
    }
    .flex-box div:nth-child(1) {
        background-color: #ffd200;
    }
    .flex-box div:nth-child(2) {
        background-color: #ff7b00;
    }
    .flex-box div:nth-child(3) {
        background-color: #00ff6a;
    }
</style>

<div class="flex-box">
    <div>box1</div>
    <div>box2</div>
    <div>box3</div>
</div>

当我们把鼠标移动到三个子元素上时,发现都没有显示出之前那种虚线区域!实际上,当长度不为绝对值时,flex 都不会显示对应的虚线区域。chrome 为什么要做这个奇怪的区分呢?想回答这个问题,我们要先看一下下面这两个例子:

<style>
    .flex-box {
        display: flex;
        width: 300px;
    }
    .flex-box div:nth-child(1) {
        background-color: #ffd200;
        width: 100px;
    }
    .flex-box div:nth-child(2) {
        background-color: #ff7b00;
        width: 100px;
    }
    .flex-box div:nth-child(3) {
        background-color: #00ff6a;
        width: 200px;
    }
</style>

<div class="flex-box">
    <div>box1</div>
    <div>box2</div>
    <div>box3</div>
</div>

我们把父容器的主轴长度指定为 300,三个子元素长度分别为 100、100、200。由于子元素的默认 flex-shrink 值为 1,即等比缩小。因此,这三个元素将按比例“平分”这超出的 100 像素,即三个容器分别缩短 25、25、50 像素。

事实上也的确如此,可以看到 chrome 已经绘制出了每个子元素对应的阴影区域。每个元素缩短的长度也和我们预料的一样。那么下面这个例子呢?注意其中 box3 的宽度从显式从 width: 200px 变成了默认的 width: auto

<style>
    .flex-box {
        display: flex;
        width: 300px;
    }
    .flex-box div:nth-child(1) {
        background-color: #ffd200;
        width: 100px;
    }
    .flex-box div:nth-child(2) {
        background-color: #ff7b00;
        width: 100px;
    }
    /* 第三个盒子没有指定宽度,而是由其内部元素将其“撑开” */
    .flex-box div:nth-child(3) {
        background-color: #00ff6a;
    }
    .flex-box div:nth-child(3) div {
        width: 200px;
    }
</style>

<div class="flex-box">
    <div>box1</div>
    <div>box2</div>
    <div>
        <div>inner box3</div>
    </div>
</div>

实际显示结果如下,可以看到,chrome 没有绘制 box3 的紫色阴影块,并且 box3 也没有被缩短!

惊了怎么会这样?答案要从 flex 执行缩放的流程说起,大致如下:

其实关键就在于 需要先确定子元素的具体长度,然后才能对剩余空间进行分配。也就是说,我们的 box3 的宽度是在第二步的时候就确定的,这时还没有计算剩余宽度:

那么问题来了,如果 box3 也参与最后的剩余空间分配的话,那是不是也要同时调整它的子元素?但是 box3 的宽度就是由其子元素提供的,如果子元素尺寸跟着调整的话,就会陷入“计算子节点长度 > 重新分配剩余空间 > 修改长度 > 子项内部元素调整 > 重新计算子节点长度”这种死循环了。所以说,长度属性为 auto 的子元素将不会参与最后的弹性缩放。


现在让我们回到最开始的问题,为什么没有明确长度属性的 flex 子元素不会显示紫色虚线块呢?因为当长度为 auto 时,其缩放结果和长度为绝对值时是有可能不一样的。chrome 正是通过这个区别显示,告诉开发者有个 flex 子元素的尺寸没有明确指定,所以最终的缩放结果和可能会和预期有所出入。

紫色虚线块和 flex-basis

事实上,上面的紫色虚线块代表的其实就是对应元素的 flex-basis 值,可以看到,这个框的尺寸在大多数情况下是和元素本身的尺寸(widthheight)是一致的,因为在默认情况下(flex-basis: auto),它的实际值就是对应元素的主轴长度。这也解释了为什么在默认情况下,flex 进行主轴元素缩放时是等比缩放的(元素所占主轴越长,要进行的缩放也就越多)。

而且,相信很多人对这个属性一直不是很清楚,这个 basis 到底是什么的基础呢,这里直接说答案:flex-basis 就是 flex 进行主轴弹性缩放的基础值。

flex 执行缩放的过程很简单,上面已经提到了,这里精炼一下::

  • 计算剩余空间:flex 会先确定每个子元素的 flex-basis 的实际值,然后用父容器的实际尺寸减去所有 flex-basis,得到的值就是剩余空间(为负说明要进行缩小)。
  • 分配剩余空间:得到了剩余空间后,flex 会使用每个子元素的分配比率来确定其可以获得多少剩余空间份额。而这个分配比例,在剩余空间为正即为 flex-grow、在剩余空间为负时则为 flex-shrink

了解了这个,我们就可以明确下面这几种组合能产生的效果(还是以上面 100、100、200 的三个盒子为例):

例一

flex: 0 1 0;

这里我们将 flex-basis 设置为 0,也就是说 flex 将会把全部的空间都拿来分配,但是又因为 flex-grow 也是 0,所以三者并不会把多的空间分掉。

这里有个有意思的小细节,由于 flex-basis 只会用在弹性缩放中,哪怕他设置为 0 也不应该影响内容的正常显示,所以就算 flex-grow 也是 0,flex 也会分配给这个元素足够显示内容的长度(取决于其子元素“撑”起来的宽度和显式指定的 width / height 哪个小),所以在这个例子里,三个 box 都获得了足够其显示出子元素的主轴空间。

该元素在没有 grow 时也获得了一些主轴空间

例二

flex: 1 1 0;

flex-basis 均为 0 时将 flex-grow 设置为 1,因为三者的 grow 都相同,所以剩余空间将被分为三等分。而三者的 basis 也都为 0 ,所以 “剩余空间”的实际值就是整个父容器空间。因此,三个 box 将会把整个父容器空间均分为三份。

例三

flex: 1 1 1;

注意哦,这里有个坑,我们可以在 flex-basis 取值 里看到,flex-basis 并不支持无单位数值,所以这个属性将被认定为无效属性,chrome devtool 里也会提示无效,从而展示默认缩放效果。

例四

flex: 1 0 0;

我们上面已经提到了,当剩余空间为负时,将使用 flex-shrink 作为缩放比率,而这里其值为 0,而缩放值乘以 0 还是 0,既每个元素都不进行缩小。因此子元素溢出了父容器。


上面简单的解释了一下新的 chrome flexbox devtool 以及相关的 flex 主轴弹性缩放细节,感兴趣的话可以用 chrome 90+ 的浏览器打开这个 flex 在线示例 尝试一下。最后咱们再来两个小问题加强一下:

问题1、定义了百分比长度的子容器

如下,父容器的长度为 300px,三个子元素的长度分别为 100px、100px、100%,问最后三者的实际长度分别为多少。

<style>
    .flex-box {
        display: flex;
        width: 300px;
    }
    .flex-box div:nth-child(1) {
        background-color: #ffd200;
        width: 100px;
    }
    .flex-box div:nth-child(2) {
        background-color: #ff7b00;
        width: 100px;
    }
    .flex-box div:nth-child(3) {
        background-color: #00ff6a;
        width: 100%;
    }
</style>

<div class="flex-box">
    <div>box1</div>
    <div>box2</div>
    <div>box3</div>
</div>

解答:分别为 60px、60px、180px。首先会将 width:100% 转换为实际的长度,而其父容器存在确定的 width: 300px,于是 box3 在缩放前的尺寸即为 300px。这里要注意的是,百分比 width 的元素是会参与弹性缩放的,因为他在确定实际长度时会往外去找父节点的大小,并不会出现 width:auto 那种死循环问题。

所以,最终就是 100、100、300 长度的三个 box 等分超出的 200px。最后就可以算出三个 box 分别缩短 40、40、120px。

问题2、form 表单项没对齐问题

这个问题是我写下这篇文章的诱因,如下是一个使用 flex 实现的多列表单的 demo,但是第二列的 label 和第一列的并没有对齐,如何解决?

<style>
    div {
        display: flex;
        width: 100%;
        margin-bottom: 10px;
    }
    span {
        width: 7em;
        text-align: right;
    }
    input {
        width: 100%;
    }
</style>

<div>
    <span>问题1:</span><input type="input" />
</div>

<div>
    <div>
        <span>问题2:</span><input type="input" />
    </div>
    <div>
        <span>问题3:</span><input type="input" />
    </div>
</div>
问题 1 和问题 2 的 label 没对齐

如果能看懂 flexbox devtool 的话这个问题其实很好解决,我们把鼠标分别放到问题 1 和问题 2 的 label 上,可以看到:

这两者的实际主轴长度是相同的(紫色虚线区域大小相同),但是由于 flex 的主轴缩放导致了问题 2 label 缩短的长度更多(问题 2 的箭头更长)。因为箭头是朝内,所以说罪魁祸首就是 flex-shrink 的默认值 1。由于第二行容纳了四个元素,并且为了占满整行宽度,两个 input 的宽度都是 100%,导致第二行的两个 span 要承担更多的缩减。

解决方法很简单,把 label span 设置为 flex-shrink: 0 即可。

写在最后

flex 布局在日常开发中是经常用到的,但是一般都只是拿来调整对齐或者自适应,对 flex 子项的属性了解还是不够深入的。借这个机会深入了解一下,如果感兴趣的话可以看一下下面参考里加粗的两篇 MDN 文章,相信会加深你对 flex 的了解。

参考

相关文章

  • 从 chrome flexbox devtool 探究 flex

    前言 自从 chrome 90 更新后,devtool 专门为 flexbox 添加了一个调试工具,只需要点击 d...

  • ReactNative布局

    FlexBox布局详解 什么是FlexBox Flex container与Flex Item FlexBox解决...

  • 【css】footer固定在页面底部

    在chrome浏览器中,采用flexbox布局。 在支持flex布局的chrome浏览器中打开,没有问题。但是在I...

  • 详解flexbox中的flex属性

    以前用flexbox布局都是简单的使用,总是有一些细节懵懵懂懂,本文通过公式的形式来探究flexbox中的flex...

  • CSS —— 盒子模型(Flexbox 布局方式)

    目录 传统盒模型 Flexbox 布局方式 Flexbox 核心概念 Flex 容器属性 flex-directi...

  • chrome devtool

    更好的利用你的浏览器调试工具~ 文档: https://developers.google.com/web/too...

  • 2018-03-29

    Flexbox布局 1.布局模型 flexbox由Flex容器和Flex项目组成,容器即父元素,项目即子元素 任何...

  • 关于Flex Css 这一篇就够了

    了解flexbox属性项最简单的方法是将flexbox属性分成两个组: flex容器属性flex item 属性 ...

  • Flexbox

    "Flex", "伸缩盒","justify", "align-items"…… 什么叫Flex? flexbox...

  • flex布局

    父元素使用display:flex 子元素:flex:1 .flexBox{ ...

网友评论

      本文标题:从 chrome flexbox devtool 探究 flex

      本文链接:https://www.haomeiwen.com/subject/zlhosltx.html