flex布局下的flex-grow、flex-shrink、flex-basis属性详解

2023-06-07,,

flex布局下的flex-grow、flex-shrink、flex-basis属性详解

Flex是Flexible Box的缩写,意为”弹性布局”,用来为盒状模型提供最大的灵活性。任何一个容器都可以指定为Flex布局。

之前学习过flex布局,也可以实现简单的一些布局,例如左侧宽度固定,右侧自适应宽度等。但在实际使用过程中总是会出现一些问题,索性花了一点时间,来好好的总结一下。

1. flex-grow属性

flex-grow属性定义剩余空间的分成。默认为0,即如果存在剩余空间,也不放大。

.item{
    flex-grow: <number> /* default 0 */
}

要了解flex-grow属性,剩余空间这个概念一定要理解。

先看一个入门的例子,当flex-grow属性都设置为1时:

<div class="as-flex">
    <div class="item-1 pink">
        <span>1 2 3 4 5 6 7 8 9</span>
    </div>
    <div class="item-1 lightblue">
        <span>1 2 3 4 5 6 7 8 9</span>
    </div>
    <div class="item-1 lightgray">
        <span>1 2 3 4 5 6 7 8 9</span>
    </div>
</div>
<style type="text/css">
    *{
        margin: 0;
        padding: 0;
    }
    .as-flex{
        display: flex;
    }
    .item-1{
        flex-grow: 1;
    }
    .pink{
        background: pink;
    }
    .lightblue{
        background: lightblue;
    }
    .lightgray{
        background: lightgray
    }
</style>

随意改变屏幕的大小,三个div块的宽度总是相等。

但是,当我们稍微改变一某个span标签中的内容,三个div块的宽度便不再相等。

页面内容其实就是三个span标签中的内容,flex-grow的逻辑是对剩余空间分成。当前的屏幕宽度为600px,三个span标签的长度分别为104px104px243.4px,那么页面剩余空间为(600-104-104-243.4)=148.6px,根据分成的比例1:1:1(flex-grow对应的值),可计算得到三个div标签的分得的剩余空间分别为49.533px(148.6/3)、49.533px49.533px,加上标签本来的长度则对应的三个div的长度分别为153.533px(104+49.533)、153.533px292.933px。页面选取对应的div,长度与计算完全吻合。同样的,如果flex-grow属性分别为1:1:2,剩余空间会按照1:1:2的比例来分成,再加上div的内容长度,就是其总长度。

下面我们看一个比较经典的布局的例子,部分长度固定,其余长度自适应。

<div class="as-flex">
    <div class="item-1 pink">
        <span>1 2 3 4 5 6 7 8 9</span>
    </div>
    <div class="item-2 lightblue">
        <span>1 2 3 4 5 6 7 8 9</span>
    </div>
    <div class="width300 lightgray">
        <span>1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9</span>
    </div>
</div>
<style type="text/css">
    *{
        margin: 0;
        padding: 0;
    }
    .as-flex{
        display: flex;
    }
    .item-1{
        flex-grow: 1;
    }
    .item-2{
        flex-grow: 2;
    }
    .pink{
        background: pink;
    }
    .lightblue{
        background: lightblue;
    }
    .lightgray{
        background: lightgray
    }
    .width300{
        width: 200px;
    }
</style>

除了第三个div的宽度为200px外,第一第二个div对剩余空间1:2分账。as-flex对应div的总长度为600px,除去固定长度200px以及第一第二个div本来占据的宽度104px(不缩放、也没有剩余空间),屏幕剩余192px,第一第二个div1:2分配剩余空间,分别分得64px128px。因此第一第二个div的长度分别为168px232px

2. flex-shrink属性

flex-shrink属性定义了项目的缩小比例。flex-shrink的默认值为1,flex-shrink的值为0时,不缩放。

.item-1{
    flex-shrink: <number>; /* default 1 */
}

as-flex对应的div的宽度小于其内元素本来宽度之和时,该属性起作用。flex-grow是对剩余空间进行分配,而flex-shrink则是对不足空间进行分配。

将上文的html片段和样式稍作修改

<div class="as-flex">
    <div class="item-1 pink">
        <span>1 2 3 4 5 6 7 8 9</span>
    </div>
    <div class="item-1 lightblue">
        <span>1 2 3 4 5 6 7 8 9</span>
    </div>
    <div class="item-2 lightgray">
        <span>1 2 3 4 5 6 7 8 9</span>
    </div>
</div>
<style type="text/css">
    *{
        margin: 0;
        padding: 0;
    }
    .as-flex{
        display: flex;
    }
    .item-1{
        flex-shrink: 1;
    }
    .item-2{
        flex-shrink: 2;
    }
    .pink{
        background: pink;
    }
    .lightblue{
        background: lightblue;
    }
    .lightgray{
        background: lightgray
    }
</style>

在屏幕宽度为300px时,其显示效果如下图图所示

三个div标签本来的宽度都为104pxspan标签的宽度),as-flex对应的div的宽度为300px,很明显,空间不够了,需要大家挤一挤,怎么个挤发,就需要按照flex-shrink的约定来让出自己的部分空间。例如,三个div原来都需要占用104px的空间,总共要占用312px的空间,现在只有300px,缺少12px。按照flex-shrink的约定,三个div按照1:1:2来分配缺少的12px,三个div分别让出3px(12/(1+1+2))、3px6px的空间,则最终三个div的实际长度分别为101px101px98px,这与浏览器中div的实际长度相等。

同样的,如果有一个div是固定宽度的话,三个div的宽度如何计算呢?看如下的例子:

<div class="as-flex">
    <div class="item-1 pink">
        <span>1 2 3 4 5 6 7 8 9</span>
    </div>
    <div class="item-2 lightblue">
        <span>1 2 3 4 5 6 7 8 9</span>
    </div>
    <div class="width308 lightgray">
        <span>1 2 3 4 5 6 7 8 9</span>
    </div>
</div>
<style type="text/css">
    *{
        margin: 0;
        padding: 0;
    }
    .as-flex{
        display: flex;
    }
    .item-1{
        flex-shrink: 1;
    }
    .item-2{
        flex-shrink: 2;
    }
    .width308{
        width: 208px;
    }
    .pink{
        background: pink;
    }
    .lightblue{
        background: lightblue;
    }
    .lightgray{
        background: lightgray
    }
</style>

还是三个div,前两个divflex-shrink的属性分别为1,2,也就是说,如果空间不足时,它们按照1:2让出自己的空间。那么第三个div在空间不足时,会如何表现呢?设置as-flex对应的div的宽度为320px,在浏览器上选取第三个div可以发现,虽然我们设置了其长度为208px,但在宽度不足时,其也随之缩小(165.633px)。由此可见,虽然我们没有设置第三个divflex-shrink属性,但其也是按一定的比例出让的自己的空间,否则第三个div的宽度不应该缩小。

具体按什么比例出让,将as-flex对应的div的宽度设置成320px,修改第三个divflex-shrink属性,得到下表:

属性 div1出让宽度 div2出让宽度 div3出让宽度 出让比例
1:2:(208px) 19.2 38.4 38.4 1:2:2
1:2:(0,208px) 32 64 208 1:2:0
1:2:(1,208px) 19.2 38.4 38.4 1:2:2
1:2:(2,208px) 90.2833 76.5667 153.15 1:2:4
1:2:(3,208px) 93.3333 82.6667 144 1:2:6

1. 三个div分别命名为div1div2div3。2. 属性1:2:(1,208px)表示div1div2flex-shrink的属性分别为1和2,div3flex-shrink属性为1,width属性为208px。3.div1div2的出让宽度为本来宽度(104px)减去当前实际宽度,div3的出让宽度为本来宽度(208px)减去当前实际宽度。4. 由于四舍五入的原因,第三第四行的出让比例为约等于,但是比例非常的接近。

由上表得出的结论为,项目的实际出让比例 = flex-shrink比例 * 实际宽度比例。例如上述例子中,项目的实际宽度比为1:1:2(104:104:208),flex-shrink属性的比例为1:2:2,则实际出让比例为1:2:4

3. flex-basis属性

flex-basis属性定义了项目占据的主轴空间。浏览器根据这个属性,计算主轴多余空间或不足空间的大小。它的默认值为auto,即项目的本来大小。

.item {
  flex-basis: <length> | auto; /* default auto */
}

上文中,我们使用的div标签的本来宽度为104px,这是浏览器自己计算出来的,而flex-basis可以帮助开发者人为的指定项目的宽度,以便于浏览器计算剩余空间或者不足空间。举个例子:

<div class="as-flex">
    <div class="item-1 pink">
        <span>1 2 3 4 5 6 7 8 9</span>
    </div>
    <div class="item-1 lightblue">
        <span>1 2 3 4 5 6 7 8 9 1 2 3 4 5</span>
    </div>
    <div class="item-1 lightgray">
        <span>1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9</span>
    </div>
</div>
<style type="text/css">
    *{
        margin: 0;
        padding: 0;
    }
    .as-flex{
        display: flex;
    }
    .item-1{
        flex-grow: 1;
        flex-shrink: 1;
    }
    .flex-basis-100{
        flex-basis: 100px;
    }
    .flex-basis-200{
        flex-basis: 200px;
    }
    .pink{
        background: pink;
    }
    .lightblue{
        background: lightblue;
    }
    .lightgray{
        background: lightgray
    }
</style>

页面显示效果如下图所示,显然屏幕宽度足够,有剩余空间,三个div按照1:1:1平分剩余空间,但是由于,项目本来长度的不同,因此三个div的实际长度必不相同。

此时项目的本来长度是浏览器根据内容自己计算出来的。利用flex-basis属性,我们可以指定项目本来长度,在上面代码的基础上,我们分别为三个div添加
flex-basis-100类,指定三个div的本来长度为100px,则显示效果如下图所示:

三个div的实际长度均为200px,这是由于对于多余的空间(600-100*3),三个div均分都为100px,而项目原始长度都为100px,因此项目的实际长度都为200px。同样的道理,as-flex对应的div宽度为240px时,空间不足,缺少60px,按照空间不足时的宽度出让规则,每个div分别出让20px的空间,所以其实际长度为80px

项目的原始长度由flex-basiswidth属性控制。flex-basis的优先级高于width属性,如果只设置了width属性,flex-basisauto,则项目的原始长度等于width,而如果同时设置了widthflex-basis,则项目的原始长度等于flex-basis。因此上文中用到width的地方可以使用flex-basis来代替。

注意:

  1. 即便在相同代码的情况下,可能会由于浏览器的原因,产生标签长度与文中不一致的地方。
  2. 本来宽度是值,当div为此宽度时,没有空间没有剩余也没有不足。
  3. 文章采用的浏览器为Firefox 61.0.1 (64 位)

文章到此结束,如有错误,请各位道友不吝赐教。