面试官:flex:1 是什么意思?

大家好,我是雷布斯。

flex 比较多的小伙伴们,肯定经常给元素设置 flex: 1; 来占满父元素的剩余空间,那么大家是否有思考过,这个属性值具体是什么意思,为什么能实现我们的样式需求呢?

我们也不卖关子,先来看下 flex 的语法。

flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]

其实很好理解, flex 属性是flex-growflex-shrinkflex-basis这 3 个 CSS 属性的缩写。

我们再来了解下,这三个属性分别代表了什么。(文章中的示例,默认的flex-direction的值都是row。)

flex-grow

flex-grow 规定在空间允许的情况下,子元素如何按照比例分配可用剩余空间:

  • 如果所有的子元素的属性都设定为 1,则父元素中的剩余空间会等分给所有子元素。
  • 如果其中某个子元素的flex-grow设定为2,则在分配剩余空间时该子元素将获得其他元素二倍的空间(至少会尽力获得)。

它的默认值为0,意味着即使有剩余空间,各子元素也不会放大。

另外,flex-grow 不能设置负值。

flex-shrink

与flex-grow属性类似,flex-shrink定义了空间不足时项目的缩小比例:

  • 如果其中某个子元素的flex-shrink值为0,则空间不足时该子元素并不会缩小。
  • 如果其中某个子元素的flex-shrink值为2时,则空间不足时该子元素会以二倍速度缩小。

flex-shrink的默认值为1,当所有子元素都为默认值时,则空间不足时子元素会同比例缩小。

flex-basis

flex-basis是大家比较容易忽略的一个属性,它定义了在计算剩余空间之前子元素默认的大小,可以设置为某个长度(比如 20%, 5rem 等)或者关键字。

它的默认值是关键字auto,代表这子元素会按照其本来的大小显示。

flex: 1 是什么的简写?

看完上面的介绍,大家知道 flex 的默认值是 0 1 auto,那么 flex: 1 代表着上面三个属性值分别是什么呢?

可能会有人觉得是 flex:1 1 auto 的简写,毕竟设置了 flex:1 后,就可以让容器扩张。

实际上,答案是 flex:1 1 0%,其中的 flex-basis 的值从默认值 auto 变成了 0%

再回到 flex 的语法。

flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]

flex: none 很好理解,元素会根据自身宽高来设置尺寸。它是完全非弹性的:既不会缩短,也不会伸长来适应 flex 容器,相当于将属性设置为 flex: 0 0 auto

再来看看 flex 设置成其他值时规则:

(1) 如果 flex 的属性值只有 1 个值,则具体规则如下:

  • 如果是数值,如 flex:1,则这个 1flex-grow 属性的值,此时 flex-shrink 属性和 flex-basis 属性的值分别是 10%。注意,这里的 flex-basis 属性是 0%,而不是默认值 auto
  • 如果是长度值,如 flex:100px,则这个 100px 显然为 flex-basis 属性的值,因为 3 个缩写的 CSS 属性中只有 flex-basis 的属性值支持长度值。此时 flex-grow 属性和 flex-shrink 属性的值都是 1,注意,这里的 flex-grow 属性的值是 1,而不是默认值 0

(2) 如果 flex 的属性值有 2 个值,则第一个值一定是 flex-grow 属性值,第二个值根据值的类型不同对应不同的CSS属性,具体规则如下。

  • 如果第二个值是数值,例如 flex:1 2,则这个 2flex-shrink 属性的值,此时 flex-basis 属性计算值是 0%,并非默认值 auto
  • 如果第二个值是长度值,例如 flex:1 100px,则这个 100pxflex-basis 属性值。

(3) 如果 flex 属性值有 3 个值,则长度值flex-basis 属性值,其余两个数值分别为 flex-growflex-shrink 的属性值。下面两行CSS语法都是合法的,且含义也是一样的:

/* 下面两行的CSS语句含义是一样的 */
flex: 1 2 50%;
flex:50% 1 2;

所以在简写的时候其实对应的计算值是这样的:

简写等同于
flex: initialflex: 0 1 auto
flex: 0flex: 0 1 0%
flex: noneflex: 0 0 auto
flex: 1flex: 1 1 0%
flex: autoflex: 1 1 auto

不太好理解是吧?张鑫旭大佬的《CSS新世界》一书中,给出了这样的解释:

为何 flex 属性会有这样与众不同的行为呢?按照CSS规范的说法,这样设计的目的是为了让 flex 属性的表现更符合我们日常开发需要的效果。

意思就是,当我们使用 flex:1 的时候,正常情况就是需要 flex-basis 为 0%,即基础尺寸为 0;当我们使用 flex:100px 的时候,正常情况就是需要 flex-grow 为 1,也就是尺寸保持向外的弹性。

flex 属性站在实用主义的角度对计算值进行了优化, 我认为这是 CSS 规范一种友善的处理,而这种友善在 flex 的关键字属性值中体现的更加明显。

总结

  • 如果想保持元素按照其宽度平铺换行的话,可以使用 flex:initial,比如说不定宽的小标签、小图标列表;
  • 如果想保持元素不随容器宽度放大和缩小,可以使用 flex:none 来实现,比如说上一篇文章中的定宽侧边栏;
  • 如果想要让各元素之间等比放大和缩小的话,可以使用 flex:1 来实现;
  • 如果想要元素根据内容的宽度来占据容器剩余空间或者缩小的话,可以使用 flex:auto 来实现;
  • flex:0 适用场景较少,适合设置在替换元素的父元素上。

最后

给大家留两个思考题:

  • flex:1 和 flex:auto 有什么区别?
  • 如果子元素全部设置 flex-grow: 1,子元素的宽度会都相等吗?

顺便也给我们的辅导服务打个广告,现在报名支持指定导师哦~