为什么 CSS floats 会为子元素添加边距?

Why do CSS floats add margins to child elements?

使用 MDN's Introduction to CSS layout 中的示例,CSS 浮动向 P 和 H2 元素添加边距。这是代码示例:

<h1>2 column layout example</h1>
<div>
  <h2>First column</h2>
  <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. </p>
</div>

<div>
  <h2>Second column</h2>
  <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut.</p>
</div>

这是 CSS(我添加了背景色以便于查看):

div:nth-of-type(1) {
  background-color: blue;
  width: 48%;
  float: left;
}

div:nth-of-type(2) {
  background-color: red;
  width: 48%;
  float: right;
}

如果您使用完全相同的代码减去浮点数,则 H2 元素上没有上边距,P 元素上也没有下边距。彩色 DIV 紧紧围绕文本。

但是,如果确实包含浮动,不仅 DIV 的布局会发生变化(如预期的那样从堆叠变为并排),而且会向 H2 元素添加上边距和底部边距margin 被添加到 P 元素。您可以清楚地看到,彩色 DIV 在顶部和底部不再紧紧围绕文本。

我可以很容易地删除这些边距:

h2 {
  margin-top: 0;
}

p {
  margin-bottom: 0;
}

它很容易修复,但我的问题是,为什么?为什么添加浮动会导致子元素自动插入不需要的边距?这种行为是预期的还是期望的?这是一个错误吗?一个特征?这对我来说似乎很奇怪且不可预测。

默认情况下,浏览器在 h2p 标签上设置了一些 margin-topmargin-bottom,根据 MDN - Mastering margin collapsing

The margins of adjacent siblings are collapsed (except when the later sibling needs to be cleared past floats).

...

If there is no border, padding ... The collapsed margin ends up outside the parent.

...

Margins of floating and absolutely positioned elements never collapse.

就在白色 CSS 之前,您可以重置所有默认浏览器样式。使用一些 CSS reseters

* {
    box-sizing: border-box;
    padding: 0;
    margin: 0;
}

这与浮动无关,只是与浏览器默认样式有关,加上元素顶部和底部的 "collapsing margins"。如果你打开 Firefox 浏览器开发者工具,有一个标记为 "calculated"(或类似的,不确定确切的英文表达)的选项卡,其中包含一个复选框 "brwoser styles"。当您检查时,您会在检查 HTML 元素时看到浏览器默认样式。