【译】flexbox交互式指南

87 阅读6分钟

本文节选翻译自《An Interactive Guide to Flexbox》

假设的尺寸(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-basiswidth属性相似;当flex-direction: column时,flex-basisheight属性相似。

众所周知呀,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-basiswidth的作用相同。我们使用flex-basis,更多是一种习惯,但如果我们使用width,我们会得到完全相同的结果。flex-basewidth设置元素的假设尺寸(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,就有下图 image.png 我们总共有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-shrinkflex-grow中只有一个可以同时激活。如果有多余的空间,flex-shrink没有效果,因为项目不需要缩小。而如果子元素们对它们的容器来说太大了,flex-grow也没有效果,因为没有多余的空间可以分割。

如何阻止收缩

有时,我们不希望flexbox的某些子元素收缩。下面这个例子,当容器变窄时,我们的两个圆就会被压成粗大的椭圆。如果我们想让它们保持圆形呢?我们可以设置flex-shrink:0来做到这点。

当我们将flex-shrink设置为0时,我们基本上是完全"退出"了收缩过程。这时Flexbox算法将把flex-basis(或width)作为一个硬性的最低限制。