flex-basis和width有什么区别?

358

有一些关于这个问题的疑问和文章,但就我所知没有什么确定性的结论。我找到的最好的摘要是:

flex-basis允许你在计算之前指定元素的初始/起始大小。它可以是百分比或绝对值。

...这本身并没有对设置了flex-basis属性的元素的行为有太多的解释。根据我目前对flexbox的了解,我不明白为什么这不能描述width

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

  • 如果我将width替换为flex-basis(反之亦然),视觉上会有什么变化?
  • 如果我把它们都设为不同的值会发生什么?如果它们有相同的值会发生什么?
  • 是否存在某些特殊情况,在这些情况下使用widthflex-basis与使用其他属性差别显著?
  • 当与其他flexbox样式(如flex-wrapflex-growflex-shrink)一起使用时,widthflex-basis有什么区别?
  • 还有其他显著的差异吗?

编辑/澄清:这个问题以不同的格式在What exactly flex-basis property sets?中被提出,但我觉得更直接地比较或总结flex-basiswidth(或height)的差异会更好。


4
最好的文章,解释flex基础、flex增长和收缩的全部内容。 - ZenVentzi
6个回答

514

考虑使用flex-direction

读到你的问题时,首先想到的是flex-basis并不总是应用于width

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

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


关键区别

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

  • flex-basis仅适用于flex项目。不是flex项目的flex容器将忽略flex-basis,但可以使用widthheight

  • flex-basis仅在主轴上起作用。例如,如果在flex-direction: column中,需要使用width属性来水平调整大小。

  • flex-basis对绝对定位的flex项目没有影响。需要使用widthheight属性。绝对定位的flex项目不参与flex布局。

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


浏览器行为

在渲染方面,除非flex-basisautocontent,否则flex-basiswidth之间应该没有区别

来自规范:

7.2.3. flex-basis属性

对于除autocontent之外的所有值,在水平书写模式下flex-basis的解析方式与width相同。

但是autocontent的影响可能非常小或根本没有。规范进一步说明:

auto

当在 flex 项上指定时,auto 关键字将主尺寸属性的值作为使用的 flex-basis 检索。如果该值本身是 auto,则使用的值为 content

content

表示根据 flex 项的内容自动调整大小。

注意:此值未出现在 Flexible Box Layout 的初始版本中,因此某些旧实现将不支持它。可以通过使用 auto 和主尺寸(widthheight)为 auto 来实现等效效果。

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


flex-shrink 因子

记住 flex 容器的初始设置非常重要。其中一些设置包括:

  • flex-direction: row - flex 项将水平对齐
  • justify-content: flex-start - flex 项将在主轴上堆叠在行的开始处
  • align-items: stretch - flex 项将扩展以覆盖容器的交叉尺寸
  • flex-wrap: nowrap - flex 项被强制保持在单行中
  • flex-shrink: 1 - 允许 flex 项缩小

请注意最后一个设置。

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

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

为了渲染指定的宽度 - 并保持其固定 - 您需要禁用收缩:

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. 灵活性的组成部分

建议作者使用 flex 的简写方式来控制灵活性,而不是直接使用其长属性,因为简写可以正确地重置任何未指定的组件以适应常见用途


浏览器问题

一些浏览器在嵌套的 flex 容器中调整 flex 项目的大小时会出现问题。

在嵌套的 flex 容器中忽略 flex-basis,但 width 可以正常工作。

当使用 flex-basis 时,容器会忽略其子元素的尺寸,导致子元素溢出容器。但是使用 width 属性时,容器会考虑其子元素的尺寸并相应地扩展。

参考文献:

示例:


使用flex-basiswhite-space: nowrap的Flex项目溢出inline-flex容器。使用width没有问题。

当渲染一个带有white-space: nowrap的兄弟元素时,似乎设置为inline-flex的Flex容器不能识别子元素上的flex-basis(尽管它可能只是一个未定义宽度的项目)。容器不会扩展以适应项目。

但是,当使用width属性而不是flex-basis时,容器将尊重其子元素的大小并相应地扩展。在IE11和Edge中不存在此问题。

参考文献:

示例:


flex-basis(和flex-grow)在表格元素上不起作用

参考文献:


当祖先容器是收缩到适合元素时,flex-basis在Chrome和Firefox中失败。 在Edge中,设置工作正常。

如上面链接中所示的示例,涉及position:absolute,使用floatinline-block也将呈现相同的错误输出(jsfiddle演示)。


影响IE 10和11的错误:


4
min-width:100px;怎么样?它可以成为禁用收缩的选项吗? - Mori
2
@Mori,是的,flex-shrinkmin-width 处停止。相应的 flex 规则应该是 flex: 1 0 100px - Michael Benjamin
2
@Mori,因为这样它就等于宽度。需要flex-grow: 1组件才能允许元素从flex-basis设置的最小宽度开始增长。 - Michael Benjamin
如果您不介意的话,您还可以扩展浏览器错误部分,以说明如果祖先元素是shrink-to-fit元素(inline-block、float、position:absolute/fixed等),则flex-basis不起作用:https://jsfiddle.net/82dx9mrw/1/...逻辑与父元素为inline-flex和嵌套flexbox相同,因为存在*shrink-to-fit*行为,但方式不同。 - Temani Afif
@TemaniAfif,已完成。谢谢。我遇到了一些与此问题相关的其他浏览器错误。我只是没有时间添加它们。我猜你的问题是受到这篇帖子的启发,你将其关闭为这篇帖子的重复,而我没有将其关闭为重复,因为那个特定的错误在这里没有被提及。 - Michael Benjamin
显示剩余8条评论

41

除了 Michael_B 的优秀总结外,值得重申的是:

flex-basis 允许你指定元素在任何其他计算之前的初始/起始大小。它可以是百分比或绝对值。

这里重要的部分是初始

独立使用时,它不会解析为宽度/高度,直到其它的 flex grow/shrink 属性开始生效。

因此,一个子元素有

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

初始宽度为25%,但随后立即尽可能地扩展,直到考虑到其他元素。如果没有其他元素...则为100%的宽度/高度。

快速演示:

.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(或缩写flex:fg fs fb)进行实验…可以得到一些有趣的结果。


我发现通常在 flex 上下文中,它们都可以设置元素的初始/起始大小:flex-basiswidth / height。例如,flex-basis: 200px 基本上与 flex-basis: auto; width: 200px; 相同。看起来当 flex-basis 没有设置为 auto 时,它就会覆盖 width / height 的值。我所看到的唯一区别是内容溢出的处理方式。 - Karolis

24

flex-basiswidth(或者根据当前书写模式是height)之间有一个关键区别,除了灵活的尺寸方面(flex-grow: 0; flex-shrink: 0;)。

这源于Flex布局中的异常情况,即flex项的自动最小大小默认为min-content,而不是通常的0。换句话说,默认的min-wdith: 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的错误位置隐含地进行了评论。

默认情况下,弹性项不会缩小到其最小内容大小(最长单词或固定大小元素的长度)。要更改此设置,请设置min-width或min-height属性。(请参见§ 4.5自动最小尺寸的弹性项。)

如评论所述,设置最小尺寸会降低边界,并将其设置为零会有效地禁用它,使flex-basis再次按预期工作。

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

其次,flex-basis不能再用于将空间分配给比例大小的盒子,而不仅仅是添加到它们的初始大小。有关更多详细信息,请参见规范中的图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>


1
这就是我一直在寻找的答案。谢谢。 - Itay Ganor
1
这部分内容“正如评论中所提到的,设置最小尺寸会降低边界,并将其设置为零有效地禁用它,使flex-basis再次按预期工作。”帮助我解决了我的问题,谢谢! - mimo
非常有用,谢谢!尤其是这个链接指向的图表:https://drafts.csswg.org/css-flexbox-1/#valdef-flex-none,我会将它添加到答案中。 - undefined

8
可能最重要的一点需要补充:
如果浏览器不支持 flex 怎么办?在这种情况下,width/height 起作用并应用其值。
定义元素的 width/height 是一个非常好的想法 - 几乎是必须的,即使你随后为 flex-basis 定义了完全不同的值。请记住通过禁用 display: flex 进行测试,并查看结果。

3
在主要的浏览器中,唯一不支持弹性布局属性的是IE < 10。http://caniuse.com/#search=flex - Michael Benjamin
1
@Michael_B 当然可以,也许只有我需要支持移动浏览器,包括任天堂3DS浏览器,该浏览器明显不支持flex - Niet the Dark Absol

5

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

如果你设置它的 flex-basis:600px,当窗口大小小于 600px 时,该盒子会收缩,你就不会看到水平滚动条。

注意,flex-basis 只适用于 flex 项目。


4

当你使用包裹(wrapping)时,这会有所不同。

举个例子,如果你将一个元素的宽度设置为0并期望它进行自动换行,那是不会发生的。但如果使用flex-basis:0,它就可以进行自动换行。(前提是不隐藏溢出部分)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接