假设的尺寸(Hypothetical size)
让我们谈谈我对Flexbox最令人大开眼界的认识之一。 比如我有如下的CSS
.item {
width: 2000px;
}
一个理智的人可能会看到这一点,然后说:"好吧,所以我们会得到一个2000像素宽的元素"。但这永远是真的吗?
让我们来测试一下。
这十分有趣,不是吗?两个元素都应用了完全相同的CSS。它们都有width: 2000px
。然而,第一个项目比第二个项目要宽得多!这是为什么呢?
不同之处在于布局模式。第一项使用流式布局,而在流式布局中,宽度是硬约束。当我们设置width: 2000px
时,我们将得到一个2000像素宽的元素,即使它会溢出父元素。
然而,在Flexbox中,宽度属性的实现方式不同。它更像是一种建议,而不是一种硬约束。
规范对此有一个名称:假设的尺寸(hypothetical size)。这是一个元素的尺寸,在一个完美的乌托邦世界里,没有任何东西妨碍它。唉,事情很少这么简单。在这种情况下,限制因素是父元素没有空间容纳一个2000px宽的子元素。因此,子元素的尺寸被缩小,以便适应父元素。这是Flexbox哲学的一个核心部分。事物是流动的、灵活的,可以根据世界的约束条件进行调整。
增长和收缩(Growing and shrinking)
要真正了解Flexbox的流动性,我们需要谈谈3个属性:flex-grow、flex-shrink和flex-basis。
flex-basis
简而言之,当flex-direction: row
时,flex-basis
与width
属性相似;当flex-direction: column
时,flex-basis
与height
属性相似。
众所周知呀,Flexbox中的一切都与主轴/交错轴挂钩。例如,justify-content
将沿主轴分配子元素,无论主轴是水平还是垂直,它的工作方式都是一样的。不过,宽度和高度并不遵循这一规则!宽度将始终影响水平尺寸,当我们把Flex方向从行翻转到列时,它不会突然变成高度。
因此,Flexbox的作者创建了一个通用的 "尺寸 "属性,称为flex-basis
。它就像宽度或高度属性一样,但与主轴挂钩。像其他flexs属性一样,它允许我们在主轴方向上设置一个元素的假设的尺寸(hypothetical size),不管是水平还是垂直。
下面的4个子元素都被设置了flex-basis:50px
,但是你可以改变第一个子元素的flex-basis
的值
就像我们看到的width
属性,flex-basis
更像是一种建议,而不是一种硬约束。在某些情况下,没有足够的空间让所有的元素都满足在它们被指定的尺寸,所以它们必须做出妥协,以避免溢出。
flex-grow
默认情况下,Flex上下文中的元素会沿着主轴线缩小到其最小的舒适尺寸。这通常会产生额外的空间。我们可以用flex-grow
属性指定该额外的空间应如何被消耗。
flex-grow
属性的默认值是0
,这意味着这种增长是可以选择的。如果我们想让一个子元素占据容器中的任何额外空间,我们需要明确地告诉它。
如果多个子元素都设置了flex-grow
怎么办?在这种情况下,额外空间将基于子元素的flex-grow
值按比例分配。我想用视觉来解释会比较容易。尝试对下面的每个子元素的flex-grow
进行递增/递减。
flex-shrink
在迄今为止我们所看到的大多数例子中,我们都有额外的空间可以利用。但是如果我们的子元素相对它们的容器来说太大了怎么办?
让我们来测试一下。试着缩小容器,看看会发生什么。 很有意思,是吧?两个子元素都缩小了,但它们是按比例缩小的。第一个子元素的宽度始终是第二个子元素的2倍。
一个友善的提醒,flex-basis
与width
的作用相同。我们使用flex-basis
,更多是一种习惯,但如果我们使用width
,我们会得到完全相同的结果。flex-base
和width
设置元素的假设尺寸(Hypothetical size)。Flexbox算法可能会将元素缩小到这个假设尺寸以下,但在默认情况下,它们总是一起缩放,并保持两个元素之间的比例。
那么,如果我们不希望我们的元素按假设尺寸(Hypothetical size)的比例缩小,该怎么办呢?这正是Flex-shrink
属性的用武之地。
我们有两个子元素,每个子元素的假设尺寸是250px
。容器至少要有500px
的宽度才能容纳这些子元素。让我们假设我们把容器缩小到400px
。那么,我们不能把价值500px
的内容塞进一个400px
的袋子里! 我们有100px
的赤字。我们的元素将需要放弃100px
的总量,以使它们能够适应。
flex-shrink
属性让我们决定如何支付该余额。像flex-grow
一样,它也是一个比率。默认情况下,两个子元素都有flex-shrink: 1
,所以每个子元素都要支付一半的余额。他们各自放弃了50px,他们的实际尺寸从250px缩小到200px。
另外,假定第一个的子元素改为flex-shrink:3
,就有下图
我们总共有
100px
的赤字。通常情况下,每个子元素都要支付1/2,但由于我们对弹性收缩(flex-shrink)进行了调整,第一个元素最终要支付3/4(75px),而第二个元素要支付1/4(25px)。
请注意,绝对值并不重要,重要的是比例。比如两个子元素都有flex-shrink:1
,每个子元素将支付总赤字的一半。再比如两个子元素的flex-shrink
都设置成1000,每个子元素将支付总赤字的1000/2000。无论哪种方式,其结果都是一样的。
不久前,我对flex-shrink
有了一个顿悟:我们可以把它看作是flex-grow
的 "反面"。它们是同一枚硬币的两面。
flex-grow
控制当子元素们小于其容器时如何分配额外空间。flex-shrink
控制当子元素们大于其容器时如何移除空间。
这意味着,flex-shrink
与flex-grow
中只有一个可以同时激活。如果有多余的空间,flex-shrink
没有效果,因为项目不需要缩小。而如果子元素们对它们的容器来说太大了,flex-grow
也没有效果,因为没有多余的空间可以分割。
如何阻止收缩
有时,我们不希望flexbox的某些子元素收缩。下面这个例子,当容器变窄时,我们的两个圆就会被压成粗大的椭圆。如果我们想让它们保持圆形呢?我们可以设置flex-shrink:0
来做到这点。
当我们将flex-shrink
设置为0时,我们基本上是完全"退出"了收缩过程。这时Flexbox算法将把flex-basis
(或width
)作为一个硬性的最低限制。