底层发生了什么
根据
inline-block width,
#a
的宽度是通过收缩适应算法计算的:
如果
width
是
auto
,则使用的值是
收缩适应宽度。
收缩适应算法(现在称为
适合内容的测量)是
min(
max-content, max(
min-content,
fill-available))
这意味着,如果有足够的空间,其宽度将是内容的最大首选宽度(即,在显式换行之外不会断开行)。否则,它将与可用空间一样宽。
然后,浏览器首先计算
#a
的首选宽度。
通常,浮动重叠以下块框,如
浮动所述:
由于浮动不在流中,因此在浮动框之前和之后创建的非定位块框垂直地流动,就像浮动不存在一样。
然后,Firefox似乎计算出了首选宽度,就好像
#b
和
#c
可以重叠。因此,首选宽度是浮动
#b
的宽度和
#c
的宽度的最大值。
但是,
#c
由于
overflow: hidden
而建立了一个新的
块格式化上下文(BFC):
具有“overflow”而不是“visible”的块框为其内容建立新的块格式化上下文。
在您的fiddle中,
#c
是一个表格,但是它是相同的,因为如
表模型中所定义,
表包装器框架建立块格式化上下文。
但是,正如
BFC next to floats中所解释的那样,BFC根不能重叠浮动:
表的边框框、块级替换元素或在正常流中建立新的块格式化上下文的元素(例如具有“overflow”而不是“visible”的元素)的边框框必须不与元素本身处于相同块格式化上下文中的任何浮动的边距框重叠。
相反,浮动可以将BFC向右“推”。这就是为什么在Chrome和Edge上,
#a
的首选宽度是
#b
和
#c
的首选宽度之和的原因。
然后,如果它不大于可用宽度,
#a
的宽度将是在前一步中计算出的首选宽度。
否则,浏览器将通过在
#b
和
#c
之间引入换行来计算首选最小宽度。因此,它将是
#b
和
#c
的最小首选宽度的最大值。
#a
的最终宽度将是该首选最小宽度和可用宽度之间的最大值。
现在已解决
#a
的宽度,因此也可以解决
#b
和
#c
的宽度。
由于
#b
被浮动,因此它也将使用收缩适应算法进行调整大小。
如果
#c
是块,则将占用剩余空间(如果没有可用空间,则将其移动到下一行)。如果它是
摘要
- 默认情况下,块级元素会填充其包含块的可用宽度。
- 如果有一个比包含块小的浮动元素,后面的块级元素将重叠在它上面,并且仍然与包含块一样宽。
- 但是,如果该后续块级元素建立了 BFC,则它将缩小以避免与浮动元素重叠,并且只填充浮动元素剩余的空间。
- 默认情况下,浮动元素或内联块级元素会尝试与其内容所需的宽度一样宽。
Chrome 和 Edge 首先检测到 BFC 根不会与浮动元素重叠,然后内联块级父元素的宽度变为浮动元素和 BFC 根的宽度之和。
相反,Firefox 最初将 BFC 根视为普通块级元素,认为它会与浮动元素重叠,并相应地计算父元素的宽度。然后检测到它是 BFC 根,防止重叠并将其缩小以适应剩余空间。
因此,差异似乎在于它们按不同顺序计算父元素的宽度并防止 BFC 根与浮动元素重叠。
不正确的行为似乎是Firefox的问题。根据非替换块的固有尺寸所定义的,首选宽度应在布局后计算,而且很可能布局包括将BFC根推到浮动旁边。
块级容器框的max-content measure是在布局后的尺寸,如果所有子元素都在max-size constraint下被定尺寸。
修复
在#c
上使用内联级别的显示方式,如display: inline-block
或display: inline-table
,可以使Firefox在计算#a
的宽度时将#b
和#c
的宽度相加。这样,如果有足够的可用空间,#c
就不会缩小,也不会出现换行。
问题在于,如果内联级别的内容太宽而无法适应浮动留下的剩余空间,则内联级别将移动到下一行而不是缩小。
.a { display: inline-block; }
.b { float: left; }
.c { display: inline-table; }
<span class="a">
<span class="b">b</span>
<span class="c">c1 c2</span>
</span>
<hr />
<span class="a">
<span class="b">longer</span>
<span class="c">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut quis diam nec ligula iaculis lacinia non ac neque. Vivamus ut condimentum enim, et sollicitudin magna. In rhoncus nisi at est rhoncus feugiat sed vitae lacus. Maecenas sed felis et libero posuere iaculis a in lacus. Quisque eleifend auctor metus, a congue sapien venenatis a. Duis mollis mauris vitae massa mollis, nec porta nulla semper. Proin fringilla et nibh ac tempor. Aenean et augue ut dui pharetra scelerisque sed sit amet dolor. Nulla posuere a lorem sit amet vehicula. Morbi nec lacinia nibh. Suspendisse lacus nulla, dignissim et mi ut, luctus lobortis nisl. </span>
</span>
或者,如果旧浏览器的支持不是问题,您可以使用flexbox。一个简单的#a { display: inline-flex; }
基本上可以工作,但以下代码更接近您当前的代码。
.a {
display: inline-flex;
align-items: flex-start;
flex-wrap: wrap;
}
.c {
flex: 1;
}
<span class="a">
<span class="b">b</span>
<span class="c">c1 c2</span>
</span>
<hr />
<span class="a">
<span class="b">longer</span>
<span class="c">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut quis diam nec ligula iaculis lacinia non ac neque. Vivamus ut condimentum enim, et sollicitudin magna. In rhoncus nisi at est rhoncus feugiat sed vitae lacus. Maecenas sed felis et libero posuere iaculis a in lacus. Quisque eleifend auctor metus, a congue sapien venenatis a. Duis mollis mauris vitae massa mollis, nec porta nulla semper. Proin fringilla et nibh ac tempor. Aenean et augue ut dui pharetra scelerisque sed sit amet dolor. Nulla posuere a lorem sit amet vehicula. Morbi nec lacinia nibh. Suspendisse lacus nulla, dignissim et mi ut, luctus lobortis nisl. </span>
</span>
#c { display: block; overflow: hidden; }
和#c { display: table }
会产生相同的结果。我最初使用了display: table
,然后尝试了display: block; overflow: hidden
作为创建BNF的替代方法。但在我的测试中,两者都产生了相同的结果。 - avernet#a
是根据收缩适应算法进行调整大小的,因此,如果有足够的空间(确实有),它应该具有所需的最大宽度,而不会在除显式换行符外的其他位置断开行。Firefox 似乎违反了这个规则。你说的ipsum
是什么? - Oriolfloat:left;
会导致初始大小从文档流中移除;请注意右边框线对齐:fiddle。 - abluejellyborder
。将它们切换到outline
,它们就会对齐 fiddle。此外,我在规范文档 http://www.w3.org/TR/CSS2/visuren.html#floats 或者 https://drafts.csswg.org/css-box-3/#float 中没有看到任何暗示浮动宽度实际上是内联的,无论父级上下文是什么。一个inline
对其内联内容进行 STF,float
是脱离文本流但影响文本流。Firefox 之所以“错误”,是因为其他浏览器做错了。 - abluejelly