flex-basis 和 width 有什么区别?

What are the differences between flex-basis and width?

已经有关于此的问题和文章,但据我所知没有定论。我能找到的最好的总结是

flex-basis allows you to specify the initial/starting size of the element, before anything else is computed. It can either be a percentage or an absolute value.

...这本身并没有说明设置了 flex-basis 的元素的行为。以我目前对 flexbox 的了解,我不明白为什么不能描述 width

我想知道 flex-basis 在实践中与 width 有何不同:


Edit/clarification:这个问题在What exactly flex-basis property sets?中以不同的形式被问过,但我觉得更直接的比较或总结flex-basiswidth(或 height)会很好。

考虑 flex-direction

阅读您的问题时首先想到的是 flex-basis 并不总是适用于 width

flex-directionrow时,flex-basis控制宽度。

但是当flex-directioncolumn时,flex-basis控制高度。


主要区别

以下是 flex-basiswidth / height 之间的一些重要区别:

  • flex-basis 仅适用于弹性项目。弹性容器(不是弹性项目)将忽略 flex-basis 但可以使用 widthheight.

  • flex-basis 仅适用于主轴。例如,如果您在 flex-direction: column 中,则需要 width 属性 来水平调整弹性项目的大小。

  • flex-basis 对绝对定位的弹性项目没有影响。 widthheight 属性是必需的。 Absolutely-positioned flex items do not participate in flex layout.

  • 通过使用 flex 属性,三个属性 – flex-growflex-shrinkflex-basis – 可以巧妙地组合成一份声明。使用 width,相同的规则将需要多行代码。


浏览器行为

就渲染方式而言,flex-basiswidth 之间应该没有区别,除非 flex-basisautocontent.

来自规范:

7.2.3. The flex-basis property

For all values other than auto and content, flex-basis is resolved the same way as width in horizontal writing modes.

autocontent 的影响可能很小或根本没有。更多来自规范:

auto

When specified on a flex item, the auto keyword retrieves the value of the main size property as the used flex-basis. If that value is itself auto, then the used value is content.

content

Indicates automatic sizing, based on the flex item’s content.

Note: This value was not present in the initial release of Flexible Box Layout, and thus some older implementations will not support it. The equivalent effect can be achieved by using auto together with a main size (width or height) of auto.

因此,根据规范,flex-basiswidth 解析相同,除非 flex-basisautocontent。在这种情况下,flex-basis 可能会使用内容宽度(据推测,width 属性 也会使用)。


flex-shrink 因素

记住弹性容器的初始设置很重要。其中一些设置包括:

  • flex-direction: row - 弹性项目将水平对齐
  • justify-content: flex-start - 弹性项目将堆叠在主轴线的起点
  • align-items: stretch - 弹性项目将展开以覆盖容器的横向尺寸
  • flex-wrap: nowrap - 弹性项目被迫保持在一行
  • flex-shrink: 1 - 弹性项目允许收缩

记下最后的设置。

因为默认情况下允许弹性项目收缩(防止它们溢出容器),指定的 flex-basis / width / height 可能会被覆盖。

例如flex-basis: 100pxwidth: 100px,加上flex-shrink: 1,不一定是100px。

要呈现指定宽度 – 并保持固定 – 您需要禁用收缩:

div {
   width: 100px;
   flex-shrink: 0;
}  

div {
  flex-basis: 100px;
  flex-shrink: 0;
}

或者,按照规范的建议:

flex: 0 0 100px;    /* don't grow, don't shrink, stay fixed at 100px */

7.2. Components of Flexibility

Authors are encouraged to control flexibility using the flex shorthand rather than with its longhand properties directly, as the shorthand correctly resets any unspecified components to accommodate common uses.


浏览器错误

某些浏览器在调整嵌套弹性容器中弹性项目的大小时遇到​​问题。

flex-basis 在嵌套的弹性容器中被忽略。 width 有效。

当使用 flex-basis 时,容器会忽略其子项的大小,并且子项会溢出容器。但是对于 width 属性,容器尊重其子项的大小并相应地扩展。

参考文献:

示例:


弹性项目使用 flex-basiswhite-space: nowrap 溢出 inline-flex 容器。 width 有效。

似乎设置为 inline-flex 的 flex 容器在呈现具有 white-space: nowrap 的兄弟项时无法识别子项上的 flex-basis(尽管它可能只是一个未定义的项目宽度)。容器不会扩展以容纳项目。

但是当使用 width 属性 而不是 flex-basis 时,容器会考虑其子项的大小并相应地扩展。这在 IE11 和 Edge 中不是问题。

参考文献:

示例:


flex-basis(和 flex-grow)无法处理 table 元素

参考文献:

  • Why does flex-box work with a div, but not a table?
  • (和边缘)

flex-basis 在 Chrome 和 Firefox 中失败,当祖父容器是收缩以适应元素时。该设置在 Edge 中运行良好。

就像上面 link 中的示例一样,涉及 position: absolutefloatinline-block 的使用也会呈现相同的有缺陷的输出(jsfiddle demo).


影响 IE 10 和 11 的错误:

除了 Michael_B 的出色总结外,还值得重复:

flex-basis allows you to specify the initial/starting size of the element, before anything else is computed. It can either be a percentage or an absolute value.

这里重要的部分是初始

就其本身而言,这会解析为 width/height 直到 其他 flex grow/shrink 属性发挥作用。

所以。一个 child 和

.child {
 flex-basis:25%;
 flex-grow:1;
}

最初将是 25% 宽,但随后会立即尽可能多地扩展,直到其他元素被考虑在内。如果有 none..它将是 100% wide/tall.

快速演示:

.flex {
  width: 80%;
  margin: 1em auto;
  height: 25px;
  display: flex;
  background: rebeccapurple;
}
.child {
  flex-basis: auto;
  /* default */
  background: plum;
}
.value {
  flex-basis: 25%;
}
.grow {
  flex-grow: 1;
}
<div class="flex">
  <div class="child auto">Some Content</div>
</div>
<div class="flex">
  <div class="child value">Some Content</div>
</div>
<div class="flex">
  <div class="child grow">Some Content</div>
</div>

使用 flex-growflex-shrinkflex-basis 进行试验 (或 shorthand flex :fg fs fb)...可以产生一些有趣的结果。

可能要补充的最重要的一点:

浏览器不支持flex怎么办?在这种情况下,width/height 接管并应用它们的值。

在元素上定义 width/height 是一个非常好的想法 - 几乎是必不可少的,即使您随后对 flex-basis 有一个完全不同的值。请记住通过禁用 display:flex 进行测试并查看您得到的结果。

似乎没有人提到 flex-basiswidth(或 height,取决于当前的书写模式)之间有一个关键区别,如果我们忽略灵活的大小方面(flex-grow: 0; flex-shrink: 0;).

它源于 Flex Layout 中的异常,即 flex 项目的自动最小尺寸默认为 min-content 而不是像通常那样为零。换句话说,默认 min-width: auto 计算为 min-content 而不是 0.

结果是,flex-basis(默认情况下)受 min-content 约束。如果您指定一个小于 min-content 的值,例如 flex-basis: 0,它将计算为 min-content。这实质上意味着(默认情况下)您不能让盒子的内容溢出,因为盒子至少有内容的大小。

这是与 width 的关键区别,后者可以任意缩小框的大小(默认),因为 min-width 默认为 0。如果width的值小于min-content,内容会溢出方框。

规范中提到了此行为,但仅在 7.1.1. Basic Values of flex.

末尾错误位置的以下注释中隐式提及

By default, flex items won’t shrink below their minimum content size (the length of the longest word or fixed-size element). To change this, set the min-width or min-height property. (See § 4.5 Automatic Minimum Size of Flex Items.)

如评论中所述,设置最小大小会降低边界,将其设置为零会有效地禁用它,从而使 flex-basis 再次按预期运行。

但也有缺点。首先,主轴没有最小尺寸属性。对于当前的 flex-direction,您必须使用正确的 min-width/min-heightmin-block-size/min-inline-size 属性。如果您更改了 flex-direction,您将需要再次找到正确的最小大小 属性。

其次,flex-basis 不能再用于将 space 分配给按比例大小的盒子,而不是简单地增加它们的初始大小。有关详细信息,请参阅规范中的 Figure 7

这是一个最小的例子。设置 min-width: 0 以使 flex-basis 再次按预期运行。

.container {
  display: flex;
}

.container div {
  background-color: lightgrey;
  border: 1px solid black;
  margin: 0 10px;
  /* disable any flexible sizing */
  flex-grow: 0;
  flex-shrink: 0;
  /* TOGGLE ME */
  /* min-width: 0; */
}

.mincontent {
  width: min-content;
}

.smallerflexbasis {
  flex-basis: 3ex;
}

.smallerwidth {
  width: 3ex;
}
<div class="container">
  <div class="mincontent">Lorem ipsum</div>
  <div class="smallerflexbasis">Lorem ipsum</div>
  <div class="smallerwidth">Lorem ipsum</div>
</div>

如果你包装的话会有不同。

比如说,您将一个子项设置为 width:0 并期望它换行,这是不会发生的。但是 flex-basis:0 它会换行。 (前提是未隐藏溢出)

如果你设置 div 的 min-width:600px,如果 window 大小低于 600px,你会看到一个水平滚动条,这不是一个好的用户体验设计。

如果您设置它的 flex-basis:600px,如果 window 大小低于 600 像素,该框将缩小并且您将看不到水平条。

请注意 flex-basis 仅适用于弹性项目。