规范背后的逻辑令人费解,涉及clearance 和collapsing margins 规则的复杂交互。
您可能熟悉传统的 CSS box model,其中 内容框 包含在 边框框内的 填充框 中 包含在 边距框:
对于将clear 设置为none 以外的元素的元素,可能会在此模型中引入一个附加组件:clearance。
“none”以外的值可能会引入clearance。 Clearance 会抑制边距折叠并充当元素顶部边距上方的间距。
换句话说,这些情况下的盒子模型看起来更像这样:
但是什么时候引入许可,应该有多大?让我们从第一个问题开始。规范says:
计算设置了 'clear' 的元素的间隙是通过首先确定元素上边框边缘的假设位置来完成的。如果元素的“clear”属性为“none”,则该位置是实际上边框边缘所在的位置。
如果元素上边框边缘的这个假设位置没有超过相关的浮动,则引入间隙,并根据 8.3.1 中的规则折叠边距。
让我们将此逻辑应用于提问者的代码。请记住,我们试图在下面的代码中解释第三个 div 的位置(添加背景以帮助可视化):
<div style="float: left; background: red;">Left</div>
<div style="float: right; background: green;">Right</div>
<div style="clear: both; margin-top: 200px; background: blue;">Main Data</div>
让我们想象一下,正如规范要求的那样,clear 在第三个 div 上设置为 none,而不是 both。那么上面的 sn-p 会是什么样子呢?
<div style="float: left; background: red;">Left</div>
<div style="float: right; background: green;">Right</div>
<div style="clear: none; margin-top: 200px; background: blue;">Main Data</div>
这里,第三个 div 重叠两个浮动 div。可是等等;为什么会这样?当然,浮动元素与块级元素重叠是允许的(根据Floats spec,“由于浮动不在流中,因此在浮动框之前和之后创建的非定位块框垂直流动,就好像浮动不存在。”),但我们的第三个 div 上面有 margin-top 的负载,并且位于两个浮动 div 之后;两个浮动的 div 不应该出现在 body 的顶部,而第三个 div 不应该出现在 200px 下方,远低于它们吗?
没有发生这种情况的原因是第三个 div 的边距折叠到 div 父级的边距(在本例中为主体 - 但如果将所有三个 div 包装在父级 div 中,也会发生相同的行为)。 Collapsing margins spec(以下引用,省略了几个不相关的细节)告诉我们:
相邻的垂直边距折叠...
两个边距相邻当且仅当:
- 两者都属于参与相同块格式化上下文的流内块级框
- 没有线框,没有间隙,没有填充,没有边框将它们分开......
- 两者都属于垂直相邻的框边,即形成以下对之一:
我们示例中的第三个 div 肯定不是 body 的 第一个孩子,但它是它的第一个 in-flow 孩子。请注意,根据https://www.w3.org/TR/CSS22/visuren.html#positioning-scheme:
一个元素被称为out of flow,如果它是浮动的、绝对定位的或者是根元素。如果元素不是外流,则称为 in-flow。
由于我们示例中的第一个和第二个 div 是浮动的,因此只有第三个 div 是流入的。因此,它的上边距与其父级的上边距相邻,并且边距折叠 - 向下推整个主体,包括两个浮动元素。因此,尽管margin-top 很大,但第三个 div 与其兄弟姐妹重叠。因此 - 在这个假设的情况下,第三个元素的 clear 设置为 none - 我们满足以下条件:
元素的上边框没有超过相关的浮动
因此:
引入清除,边距按照 8.3.1 中的规则折叠
清仓多少?该规范为浏览器提供了两种选择,并附有一些澄清说明:
然后将清除量设置为以下两者中的较大者:
- 放置块的边界边缘所需的量,即使是要清除的最低浮动的底部外边缘。
- 将块的顶部边框边缘放置在其假设位置所需的数量。
或者,间隙精确设置为放置块边界边缘所需的量,即使要清除的最低浮动的底部外边缘也是如此。
注意:这两种行为都允许等待评估其与现有 Web 内容的兼容性。未来的 CSS 规范将需要其中之一。
注意:间隙可以是负数或零。
在我们开始应用这些规则之前,我们立即遇到了难题。还记得在clear 是none 的假设 情况下我们必须考虑的折叠边距吗?嗯,它不存在于我们正在计算要使用的许可的这种非假设案例中,因为许可的存在会抑制它。回想一下前面引用的 collapsing margin rules from 8.3.1,它规定边距仅在以下情况下相邻:
(强调添加)。因此,第三个 div 的上边距和其父级的上边距不再相邻。我们可以在我们的示例 sn-p 中模拟这种预清除场景,方法是保留 clear: none,但将 padding-top: 1px 添加到正文中,这也禁用了边距折叠,根据上面引用的规则。
body {
padding-top: 1px;
}
<div style="float: left; background: red;">Left</div>
<div style="float: right; background: green;">Right</div>
<div style="clear: none; margin-top: 200px; background: blue;">Main Data</div>
现在,与边距折叠时不同,我们的第三个 div 舒适地低于它的两个浮动兄弟。但是我们已经决定,基于边距确实崩溃的假设场景,必须添加间隙;剩下的就是选择清仓的数量,以便:
将块的边框边缘与要清除的最低浮动的底部外边缘对齐
所以我们别无选择,只能对第三个 div 应用 负 间隙,以便将其顶部 边界边缘 向上拖动以接触底部 其上方浮动元素的外边缘(也称为margin edge)。因此,如果浮动元素的高度均为 10px,并且第三个 div 的上边距为 200px,则将应用 -190px 的间隙。最后,我们得到了提问者看到的最终结果:
<div style="float: left; background: red;">Left</div>
<div style="float: right; background: green;">Right</div>
<div style="clear: both; margin-top: 200px; background: blue;">Main Data</div>
(请注意,如果您使用浏览器的开发工具检查上面 sn-p 中的第三个 div,您仍然可以看到 div 上方 200px 的上边距,超出所有其余内容- 只是整个边距框都被大的负间隙向上拖了。)
简单!