likes
comments
collection
share

flex布局中的“压缩事件”

作者站长头像
站长
· 阅读数 43

前言

众所周知,flex布局应该是目前所有前端开发同学使用最多的一种,布局解决方案。但是于此同时,flex布局也像是一个”小恶魔”一样,带来一些奇怪的问题。

尤其是当我们使用flex这个属性的时候,很多同学还只停留在“使用flex: 1;可以自动占满剩余空间”,今天也是正好说一下,我在实际开发中遇到的“flex小恶魔”的《压缩事件》

问题出现

大家在写表单的时候应该都会经常用到这样的表单样式:

flex布局中的“压缩事件”

这对所有前端开发者以及前端用户来说,应该都是很常见的内容,大部分这种情况下我们会使用类似于Form表单组件来进行这样布局的开发。那么如果我们自行使用flex布局手动来实现这样页面结构的时候,会遇到什么样的问题呢?

老规矩,先上示例:

简单来讲我们所开发的dom结构大概应该是这样的:

flex布局中的“压缩事件”

样式应该是这样的:

flex布局中的“压缩事件”

页面也很显然的按照我们所想的样子渲染出来了:

flex布局中的“压缩事件”

在我们看来一切都是这么的美好,那么问题究竟出现在哪里呢?让我们想象另一个常见的场景:我们现在有一个数据展示的表格页面,而表格顶部很多个均匀分布的筛选项排列在一起。

正常情况下的时候,他们是可以友好的排列在一起的

flex布局中的“压缩事件”

可是一旦有一个筛选项很长的时候,页面就会有一定的几率变成这样

flex布局中的“压缩事件”

为了解决左侧的label被压缩的问题,我们理所当然的祭出了常用技能——flex-shrink来解决这个问题,我们只需要把这个属性的值设置为0,那么就没有元素再胆敢欺负我们的label标签了,再结合我们添加给Select组件的flex-grow: 1,我们理所当然的认为,页面就应该展示为这个样子来满足我们的期望。

flex布局中的“压缩事件”

可是实际上,这样却为我们带来了新的问题,我们的Select标签并没有如我们所愿的仅仅占满剩余空间,反而是挤压了右侧的空间。

flex布局中的“压缩事件”

探索原因

为了探究为什么页面会变成这个样子,让我们先《走进flex》。

首先,让我们看看亲爱的阮一峰大神是怎么解释flex-shrink和flex-grow这两个属性的:

flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。

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

如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。

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


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

如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。

如果仅仅根据这个文档来判断的话,我们所书写的样式应该是毫无破绽的,可是为什么我们设置为flex-grow: 1的内容超出父元素了呢?作为一个严谨的“科学工作者”(码农),我决定还是要继续一探究竟。

让我们先看一下w3c中flex的规范是怎么样描述flex-grow这个属性的:

<‘flex-grow’>

This  component sets flex-grow longhand and specifies the flex grow factor, which determines how much the flex item will grow relative to the rest of the flex items in the flex container when positive free space is distributed. When omitted, it is set to 1.

通过阅读上面这段话我们可以发现,对于产生我们上述状况的原因,可以说是没有*用,但是在翻阅规范的过程中,我们可以看到有一些内容是关于flex布局整体的边距与填充有关的内容。

The margins of adjacent flex items do not collapse.

Percentage margins and paddings on flex items, like those on block boxes, are resolved against the inline size of their containing block, e.g. left/right/top/bottom percentages all resolve against their containing block’s width in horizontal writing modes.

Auto margins expand to absorb extra space in the corresponding dimension. They can be used for alignment, or to push adjacent flex items apart. See Aligning with auto margins.

阅读这部分内容的时候如果我们单独从字面意思来解读的话其实难免会有一些晦涩,但是我们可以看到一个很重要的名词,那就是containing block

A rectangle that forms the basis of sizing and positioning for the boxes associated with it. Notably, a containing block is not a box (it is a rectangle), however it is often derived from the dimensions of a box. Each box is given a position with respect to its containing block, but it is not confined by this containing block; it can overflow. The phrase “a box’s containing block” means “the containing block in which the box lives,” not the one it generates.

In general, the edges of a box act as the containing block for descendant boxes; we say that a box “establishes” the containing block for its descendants. If properties of a containing block are referenced, they reference the values on the box that generated the containing block. (For the initial containing block, values are taken from the root element unless otherwise specified.)

See [CSS2] Section 9.1.2 and Section 10.1 and CSS Positioned Layout 3 § 2.1 Containing Blocks of Positioned Boxes for details.

通过对containing block这个概念的阅读我们不难发现,其实造成我们上述现象的原因就在其中,正是由于overflow也就是溢出,也就是说由于我们的元素内容超出了他本应该展示的范围而造成了这样盒模型溢出的现象,从而遮挡了后面元素的内容,阻碍了页面的正常展示。

尝试解决

既然知道了造成问题的原因,那么接下来我们就可以对症下药,治病!!!

1. overflow: hidden;

这其实就是对于前端来说最常用的一种解决方案,当面对这种样式溢出的问题时直接使用这个属性可以解决我们的大部分问题。

2. min-width: 0;

除了这种我们常见的方案可以解决的现象外,总会有一些情况是游离状况之外,我们无法用常规手段来解决的奇奇怪怪的问题出现在我们的职业生涯中。

比如在某些情况下,由于我们对元素的外层设置了overflow: hidden会导致,一些需要在当前元素内弹出的内容无法正常展示,比如Select的Option等等。。。那么遇到这种情况该怎么办呢?不要慌!掏出手机来发个朋友圈(不是,这种时刻就是我们的min-width来解决问题了。

按照我的个人理解,因为我们设置的flex-grow: 1属性会让元素在默认情况下占满块内的剩余空间,但是当我们突然变更内容超出当前宽度是,当前的盒模型无法自适应的缩小,而会被固定的宽度所限制住,导致元素溢出遮盖页面其他元素,但是当我们对目标元素设置一个min-width: 0的时候,我们元素默认可以被压缩的最小宽度变为0,也就成功的实现了让我们的目标元素在“剩余所有空间”与“0”之前变动,从而完美适应当前盒模型,拒绝溢出!!!

总结

其实针对我们最开始提出的问题,大部分情况下我们都可以通过常规手段,也就是overflow: hidden来解决问题。但是当我们的overflow: hidden无法完美解决我们当前的问题时,大家是否能够打开思路不被我们的固有思维所局限住,就如同在面对溢出也就是overflow的问题时是否只有通过overflow本身来解决问题这一个途径一样。希望大家在之后遇到问题时都能发散对待、归纳总结,在此也祝各位更上一层楼

参考文献