译者注: 在html中若一个元素的css设置为display: flex, 则这个元素就是flex container , 其子元素为flex item, 若是直译过来就是弹性容器和弹性项目 。 但是译者认为直译过来不好理解, 且不变记忆(就像我们常说TCP而不会说传输控制协议一样), 因此在此文中, 译者将不会翻译为flex container 和flex item, 而是翻译为flex容器和flex子元素。 同样, 在原文中有些单词(如items, flex-items, container), 我会根据情况译为flex容器和flex 子元素。请各位读者理解。

如果各位读的不舒服, 请阅读原文!

在这篇指南中我们将探索应用于flex子元素的三个属性, 它们能使我们在主轴方向上控制flex子元素的尺寸和伸缩性— flex-grow, flex-shrink, 和 flex-basis. 充分了解这些属性如何与增长和缩小的flex 子元素一起工作是掌握Flex 布局的关键所在.

预览

这三个属性控制一个flex子元素的一下几个方面:

  • flex-grow: 这个flex子元素得到(伸张)多少positive free space?
  • flex-shrink: 从这个flex子元素要消除(收缩)多少negative free space?
  • flex-basis: 在flex子元素未伸张和收缩之前,它的大小是多少?

以上属性通常用一个简写属性flex 表达. 下面的代码设置 flex-grow 属性值为 2, flex-shrink 属性值为 1 ,flex-basis 属性值为auto.

.item {
  flex: 2 1 auto;
}

如果你阅读过文章 flex布局的基本概念, 那么你应该已经对这些属性有了初步了解. 为了让你能明白当你在用它们的时候浏览器在做什么, 我们将进一步探讨它们.

工作于主轴的重要概念

在考虑flex属性如何在主轴方向上控制比率之前, 有一些概念值得我们去深究. 这涉及到flex子元素在任何伸缩之前的自然尺寸, 以及自由空间的概念

Flex子元素的尺寸

为了计算出有多少可用空间能布局于flex子元素, 浏览器必须知道这个item有多大才能开始. 它是如何解决没有应用于绝对单位的宽度和高度的flex子元素?

在 min-contentmax-content  的CSS中有一个概念— 这些关键字定义在 CSS Intrinsic and Extrinsic Sizing Specification, 并且可以用一个 length 单位代替.

例如下面的例子, 我有两段包含一个文本字符串的段落. 第一段设置了min-content的宽度. 在支持这个关键字的浏览器你可以看见文本已尽可能抓住机会来自动换行, 变得尽可能小且没有溢出. 此之后就是那个字符串的 min-content 大小. 本质上讲, 字符串中最长的单词决定了大小.

第二段设置了 max-content值, 且它和min-content想反. 它会变得尽可能大, 没有自动换行的机会. 如果flex容器太窄, 它就会溢出其自身的盒子.

如果你的浏览器不支持这些属性, 那这两段会在块流中被渲染为正常流; 下面的截图展示了预期的渲染.

The first paragraph is wrapped to the longest word, the second stretched out so as to cause overflow.

记住这种行为,以及 min-contentmax-content 对我们本文后探索 flex-growflex-shrink 的影响.

正负自由空间

译者注:positive and negative free space 直译过来就是正负空闲空间, 为了读者能良好的阅读下文, 译者先大概说下。

Flex 布局中有flex容器和flex子元素, flex子元素包含在flex容器中, 那么当flex子元素在主轴上的尺寸(大小)之和小于flex容器 的尺寸时, flex容器中就会有多余的空间没有被填充, 这些空间就被叫做 positive free space。当flex子元素在主轴上的尺寸之和大于flex容器的尺寸时, flex容器的空间就不够用,此时flex子元素的尺寸之和减去flex容器的尺寸(flex 子元素溢出的尺寸)就是negative free space, 这个negative free space加上flex容器的尺寸刚好可以容纳flex子元素.

为了不翻译花了, 译者不对positive free space和negative free space进行翻译

去谈论这些属性之前我们需要理解positive free space和negative free space的概念. 当一个flex 容器有positive free space时, 它就有更多的空间用于在flex容器内显示flex子元素. 比如说, 如果我有500px 宽的flex容器, flex-direction 属性值为 row, 三个100px 宽的flex子元素,  而且我还有200px 的 positive free space, 那么如果我想让它们(positive free space)填充flex容器,它们就可以填充在flex子元素之间.

Image showing space left over after items have been displayed.

当flex子元素的自然尺寸加起来比flex容器内的可用空间大时,我们产生了negative free space. 如果我有一个像上面500px 宽的flex容器, 但是三个flex子元素每个都为200px 宽, 我就一共需要600px 宽, 因此我就有了100px的negative free space. 这可以从flex子元素中删除以使其能适应flex容器.

The items overflow the container

我们需要理解positive free space 的分配和negative free space 的移除, 这样才能理解flex 属性.

下面的例子我会将属性 flex-direction 设置为row, 因此flex子元素的尺寸只有来自于它们的宽. 我们通过比较flex子元素和flex container的宽度来计算positive and negative free space. 你同样可以用flex-direction: column 测试每个例子. 主轴变为列后, 你需要比较flex子元素和flex容器 的高度来计算positive and negative free space.

flex-basis 属性

flex-basis 属性在任何空间分配发生之前初始化flex子元素的尺寸. 此属性的初始值为 auto. 如果 flex-basis 设置为 auto , 浏览器会先检查flex子元素的主尺寸是否设置了绝对值再计算出flex子元素的初始值. 比如说你已经给你的felx子元素设置了200px 的宽,则200px 就是这个flex子元素的 flex-basis.

如果你的flex子元素 为自动调整大小, 则auto 会解析为其内容的大小.  此时你所熟知的min-content和max-content大小会变得有用,  flexbox 会将flex子元素的 max-content 大小作为 flex-basis. 下面的例子可以证明这一点. 

在这个例子中我创造了一些列固定的盒子, 它们的 flex-growflex-shrink 都设置为 0. 这里我们看看第一个flex子元素怎么样了 — 它的150px 显示宽度被设置为主尺寸— 即设置flex-basis为150px, 然而另外两个flex子元素 没有设置宽度而是更具它们内容的宽度设置尺寸, 

除了关键字 auto 以外, 你还可以使用关键字 content 作为 flex-basis的值. 这会导致 flex-basis 根据内容大小设置即使flex子元素 设置了宽度. 这是一个新关键字而且获得浏览器支持的比较少, 但是你还是可以通过设置flex-basis: auto并确保你的flex子元素没有设置宽度来达到相同的效果 , 以便它能自动调整大小.

空间分配时, 如果你想flexbox 完全忽略flex子元素的尺寸就设置flex-basis0. 这基本上告诉flexbox所有空间都可以抢占,并按比例分享. 随着我们继续关注flex-grow,我们将看到这方面的例子。

flex-grow 属性

 flex-grow 属性指定了flex增长值, 这决定了当positive free space分配时,flex子元素相对于flex容器中的其余flex子元素的增长程度.

如果你所有的flex子元素 设置了相同的flex-grow属性值,那么空间将会在flex子元素 之间平均分配. 如果你想要这种情形,通常你需要使用1作为值,而且如果你喜欢你还可以将它们的flex-grow都 设置为88, 或100, 或1.2  —这只是个比例. 如果flex-grow的值全部相同, 并且在flex容器 中还有positive free space , 那么它(positive free space)就会平均的分配给所有的flex子元素

结合flex-growflex-basis

根据flex-growflex-basis的相互影响, 有些东西会变得迷惑起来. 让我们考虑三个不同内容大小的flex子元素的例子, 应用于下列flex规则:

flex: 1 1 auto;

这个例子中设置flex-basis的值为auto且没有设置它们的宽, 因此它们是自动调整大小的. 这意味着flexbox的大小决定于全部flex子元素内容的max-content 大小. 在布局完flex子元素 之后在flex容器中还有一些positive free space, 展示在这幅图片的阴影区域中:

Images shows the positive free space as a hatched area

我们使用与内容大小相等的flex-basis,以便从总可用空间(flex容器的宽度)中减去可用分配空间,然后剩余空间在每个flex子元素之间平均分配. 我们比较大的flex子元素最终会变得更大,因为它一开始就有一个比较大的尺寸,即使它与其他flex子元素具有相同数量的分配空间:

The positive space is distributed between items

如果你真正想要的是三个同样尺寸的flex子元素,即使它们开始是不同的尺寸,你应该使用这个:

flex: 1 1 0;

我们要说的是,为了我们的空间分配,flex子元素的尺寸计算值是0--所有空间都用来争夺,并且所有flex子元素具有相同的flex-grow 值,它们(flex子元素)每个都获得相等的空间分配。 最终结果是三个宽度相等的可伸缩 flex子元素.

尝试在这个现场示例中将flex-grow的值从1更改为0以查看不同的行为:

flex items 设置不同的flex-grow值

我们对flex-growflex-basis如何工作的理解使我们能够通过分配不同的flex-grow值来进一步控制我们单个flex子元素 大小. 如果我们设置flex-basis值为0则所用空间都可以被分配, 我们可以给每个flex子元素分配不同的flex-grow值.  在下面的示例中, 我会使用下面的值:

  • 设置第一个flex item的flex-grow值为1.
  • 设置第二个flex item的flex-grow值为1.
  • 设置第三个flex item的flex-grow值为2.

flex-basis值为 0 意味着可用空间会根据设置分配. 我们需要增加flex 增长值, 就需要在flex容器中用positive free space的总大小除以flex-grow值之和, 在这个例子中为4. 我们就可以根据个体值(flex-basis值)分配空间 — 第一个flex子元素得到一个单位 , 第二个flex子元素得到一个单位, 第三个flex子元素得到二个单位. 也就是说第三个flex子元素是第一个和第二个flex item的两倍.

记住你要在这里使用正值. 这是一个项目和另一个项目之间的比例. 你还可以使用大的数字,或者小数 — 这取决于你.把上例中分配的值更改为.25.25.50 并去测试— 你会得到相同的结果.

flex-shrink 属性

 flex-shrink 属性指定了flex 缩小值, 它确定在分配negative free space时,flex子元素相对于flex容器中其余flex子元素收缩的程度.

该属性用于处理浏览器计算flex子元素的flex-basis值的情形, 并检测它们太大以至于无法适应flex容器. 只要flex-shrink有正值则flex子元素就会收缩以至于它们不会溢出flex容器.

因此 flex-grow 用于添加可用空间, flex-shrink 减少空间来使盒子适应它们的容器而不溢出.

下一个示例中我的flex容器有三个flex子元素,我已经给它们每一个(flex子元素)设置了200px的宽度, 并且设置容器(flex容器)500px 宽. 设置flex-shrink 为 0 的flex子元素 不允许收缩以致于它们溢出了盒子.

改变 flex-shrink 值为 1 你会发现每个flex子元素 都收缩了同样大小的量, 现在所有flex子元素都适应盒子. 这样做后它们已变得比它们的初始宽度还小.

结合flex-shrinkflex-basis

你可以看见 flex-shrinkflex-grow  工作的一样好. 但是它们有两个原因使它们不完全一样.

即使它微不足道, 但规范中的定义内容是 flex-shrink不全相同与negative space的一个原因, 正如flex-grow不全相同于positive space一样:

“注意: 当分配negative space时,flex基本大小乘以flex增长值. 这会根据flex子元素能够缩小的比例(多少)分配negative space, 其它亦如此.在较大的flex子元素 明显缩小之前, 较小的flex子元素 不会缩小到0.”

第二个原因是在negative free space消除期间flexbox会阻止小的flex子元素缩小到0. 这些flex子元素会以min-content的大小进行铺设  —这个大小是它们利用任何可以利用的自动断行机会后所变成的.

在下面的例子中,在 flex-basis 解析为内容大小的位置你会看到 min-content 的铺设,. 如果你改变flex容器的宽度 — 比如增加到700px 宽 — 再减少flex子元素的宽度, 你会看到前两个flex子元素 将换行, 但是它们绝不会小于min-content的大小. 随着盒子变得越来越小,空间随后从第三个flex子元素 中移除.

在实践中,收缩行为会倾向于给你合理的结果。 你通常不希望自己的内容完全消失,或者文本框比自己的最小内容要小,因此上述规则对于需要缩小以适应容器的内容的合理行为而言是有意义的.

Giving items different flex-shrink factors

在 flex-grow值相同的情形下, 你可以给flex子元素 设置不同的 flex-shrink 值. 假如你想让一个flex子元素 比它的兄弟元素收缩的更快或更慢, 或者不在收缩, 这回改变它的默认行为.

在下面的示例中第一个flex子元素设置 flex-shrink 的值为1, 第二个为 0 (因此它将不会收缩), 第三个为 4. 第三个flex子元素比第一个收缩的更快. 任意设置不懂的值 — 你可以给 flex-grow 使用小数或者大一点的数. 选择对于你来说任意合理的数.

掌握Flex items的大小

真正理解flex子元素如何工作的关键是理解有多少东西参与影响flex子元素. 思考以下方面, 哪些是我们在这些指南中已经讨论过了的:

什么设置flex item 的基本大小?

  1. flex-basis设置为auto吗,这个flex子元素设置了宽度吗?如果设置了, flex子元素的大小将会基于设置的宽度.
  2. flex-basis 设为 auto 还是content (在支持的浏览器中)? 如果是auto, flex子元素的大小为原始大小.
  3. flex-basis是不为0的长度单位吗?如果是这样那这就是flex子元素的大小.
  4. flex-basis 设为 0呢? 如果是这样,则flex子元素的大小不在空间分配计算的考虑之内.

我们用可用空间吗?

flex子元素没有positive free space 就不会增长, 没有negative free space 就不会缩小.

  1. 如果我们把所有的flex子元素加起来并且加上它们的宽度(如果在列方向工作则为高度),总和是否小于flex容器的总宽度(或高度)? 如果是这样,那么你有 positive free space,并且flex-grow会发挥作用.
  2. 如果我们把所有的flex子元素加起来并且加上它们的宽度(如果在列方向工作则为高度),总和是否大于flex容器的总宽度(或高度)? 如果是这样,那么你有negative free space,并且flex-shrink会发挥作用.

分配空间的其他方式

如果我们不想空间添加到flex子元素中, 记住你可以在flex容器中使用指南中所描述的对准属性来处理flex子元素之间或者flex子元素周围的空闲空间, 以致可以对齐flex子元素. justify-content 属性能够在flex子元素之间或flex子元素周围分配空闲空间. 您还可以在flex子元素上使用自动边距来吸收空间并在flex子元素之间创建间距.

随着所有的flex工具的使用,你会发现大多数任务都可以实现,尽管在开始时可能需要一些实验.

文档标签和贡献者

此页面的贡献者: tianqingyu, helloyong
最后编辑者: tianqingyu,