CSS学习笔记-flex 布局

最近在项目开发的时候遇到一个问题,就是在 flex 布局的时候,设置了 flex 元素高度的时候,发现高度设置完没有生效,需要设置 flex 元素的 flex-shrink 属性为 0 才能生效,这是为啥?

想要理解这个问题,需要理解下面这三个 flex 元素的属性

  • flex-grow:该元素获得(伸张)多少正可用空间(positive free space)?
  • flex-shrink:该元素要消除(收缩)多少负可用空间(negative free space)?
  • flex-basis:在该元素未伸张和收缩之前,它的大小是多少?

这篇文章主要介绍通过这三个属性的使用来探索 flex 的布局机制。

这里先介绍一下 fle 布局中可用空间的概念,CSS中的"可用空间"(available space)是指在布局中可供使用的剩余空间,它通常指的是容器内的剩余可分配空间。

举个例子说明一下可用空间,假设在 1 个 500px 的容器中,我们有 3 个 100px 宽的元素,那么这 3 个元素需要占 300px 的宽,剩下 200px 就是可用空间。在默认情况下,flexbox 的行为会把这 200px 的空间留在最后一个元素的后面。

Untitled

通过几个例子来探讨这三个属性的使用

# flex 容器高度足够高的布局场景

标题的含义具体是指,flex 容器的高度比所有 flex 元素高度的总和还要高,即能完全容纳下 flex 元素。这种情况下通常留出一部分可用空间。

在下面这种布局情况下,假设我们希望最后一个蓝色元素填满剩余的可用空间应该如何设置?

Untitled

<div class="flexlayout-container-one">
  <div class="item-one">第一个</div>
  <div class="item-two item-size">第二个</div>
  <div class="item-three item-size"></div>
</div>
<style>
.flexlayout-container-one {
  display: flex;
  flex-direction: row;
  width: 400px;
  height: 100px;
  background-color: aquamarine;
}
.item-one { background-color: red; }
.item-two {
  background-color: green;
  width: 100px;
  height: 100px;
}
.item-three {
  background-color: blue;
  width: 150px;
  height: 100px;
}
</style>

# flex-basis 简介

先别急,我们先理解一下 flex-basis 的概念,flex-basis 指定了 flex 元素在主轴方向上的初始大小。flex-basis 可以被设置为一个固定的长度值(如像素、百分比等)或者 auto,当 flex-basis 被设置为 auto 时,弹性元素的初始尺寸会根据内容的大小自动确定。

注意:flex 元素的 width 属性和 flex-basis 属性是有区别的,只不过当 width 属性设置为 150px 的时候 flex-basis 也是 150px

结合上面这个例子,item-one 元素的 flex-basis 值为 auto,item-twoitem-threewidth 元素设置 150px,即 flex-basis 也是 150px.

# flex-grow 简介

flex-grow 是 Flexbox 布局中的一个属性,用于定义弹性元素在主轴(通常是水平轴)上的放大比例,以便在剩余的可用空间中分配额外的空间。

flex-grow 接受一个非负数值作为参数,表示元素的放大比例。这个值越大,元素在可用空间中获得的额外空间就越多。默认情况下,元素的 flex-grow 值为 0,意味着它不会在分配额外空间时放大。

OK,现在的知识储备已经足够解决上面的问题了。

回到我们例子中,我们想让最后的蓝色节点填满可用空间,可以如下设置这样蓝色节点

.item-three {
	background-color: blue;
	width: 150px;
  height: 100px;
  flex-grow: 1; /* 元素会在剩余空间中均等地分配额外空间 */
}

Untitled

设置了 flex-grow 为 1 的元素会均等的共享剩余的可用空间,目前只有蓝色节点设置了 flex-grow 为 1,所以蓝色区域共享了所有的剩余空间。值得说明一下的是,这时候蓝色节点的宽度虽然设置的是 150px,但是宽度的设置已经不起作用了。

如果想要蓝绿色共享可用空间,则将绿色的节点元素也设置 flex-grow 为 1。

.item-two {
	background-color: green; 
	width: 100px;
  height: 100px;
  flex-grow: 1; /* 元素会在剩余空间中均等地分配额外空间 */
}

效果如图,蓝色和绿色节点平分了剩余的控件,假设可用空间为 100px,则 50px 分给绿色节点,50px 分给蓝色节点。最终绿色节点为 150px, 蓝色节点为 200px。

Untitled

# flex 容器高度不足的布局场景

标题的含义具体是指,flex 容器的高度比所有 flex 元素高度的总和要小,即能不能完全容纳下 flex 元素。

在下面这种布局情况下,我们希望红色和绿色能够按照正常的显示,然后蓝色节点被压缩也没关系。

Untitled

<div class="flexlayout-container-two">
  <div class="item-one">第一个</div>
  <div class="item-two item-size">第二个</div>
  <div class="item-three item-size"></div>
</div>
.flexlayout-container-two {
  margin-top: 20px;
  display: flex;
  flex-direction: row;
  width: 200px;
  height: 100px;
  .item-one { background-color: red; }
  .item-two {
    background-color: green;
    width: 100px;
    height: 100px;
  }
  .item-three {
    background-color: blue;
    width: 150px;
    height: 100px;
  }
}

回到我们上面的知识点,目前这种布局下是没有可用空间的,空间都被填满了,而且本来设置好宽度的元素,宽度也被挤压了。这种情况怎么达到预期的效果?

# flex-shrink 简介

flex-shrink 是 Flexbox 布局中的一个属性,用于定义弹性元素在主轴上的缩小比例。当容器的空间不足以容纳所有弹性元素时,具有非零 flex-shrink 值的元素会按照其缩小比例来收缩,以适应剩余的空间。

flex-shrink 属性接受一个非负数值作为参数,表示元素的缩小比例。默认情况下,元素的 flex-shrink 值为 1,意味着它会根据容器空间的不足等比例地缩小。如果一个元素的 flex-shrink 值为 0,它将不会在容器空间不足时缩小。

我自己理解 flex-shrinkflex-grow 是两组相对的概念,一个是出现在空间不足的场景,一个是出现在空间富裕的场景。

了解了 flex-shrink 属性之后,我们回到上面的例子,因为默认 flex-shrink 是 1,上面所有 flex 容器内的元素都会等比例缩小,想要不缩小的话就要设置 flex-shrink 为 0,所以我们对红色和绿色元素节点进行如下配置,得到效果如图

.item-one {
  background-color: red;
  flex-shrink: 0;
}
.item-two {
  background-color: green;
  width: 100px;
  height: 100px;
  flex-shrink: 0;
}

Untitled

# 回到起始问题

写到这儿也就足够能解释文章开通的问题了「在 flex 布局的时候,设置了 flex 元素高度的时候,发现高度设置完没有生效,需要设置 flex 元素的 flex-shrink 属性为 0 才能生效,这是为啥?」

因为 flex 容器高度不够,设置 height 没有生效,设置 flex-shrink 为 0 的话,就不会因为空间不足而压缩了。这个方式

因为 flex 容器高度不够,设置 height 没有生效,设置 flex-shrink 为 0 的话,就不会因为空间不足而压缩了。

这种设置方式其实很适合在列表高度不固定的时候,进行列布局,想要在列表底部撑起一块空白区域的场景,单独设置一个空白节点,然后设置起 flex-shrink 为 0,然后设置想要撑起的空白区域的高度即可。

# 总结

我自己理解 flex-grow 是用在可用空间富裕的场景下,flex-shrink 用在没有可用空间或者 flex 容器没有设置 height 的情况下。

参考地址:

  1. MDN-flex 布局的基本概念 (opens new window)
  2. MDN-常规流中的块和内联布局 (opens new window)
  3. MDN-flex-basis (opens new window)