为什么给一个元素设置清除浮动后margin-top无效? (该元素和其前面的浮动元素有一个包裹层)


codepen在线演示:
http://codepen.io/medifle/pen/qdwpje

div.flo是左浮动元素, div.b3清除了浮动, 其margin-top却被忽略掉了. 注意这两个元素由一个section元素包裹.

下面是我观察到的一些情况:

  1. 如果没有这个section包裹, 则div.b3的margin-top有效.

  2. 如果给这个包裹用的section元素用任何防止 margin collapsing 的方法(比如说设置'overflow: hidden;', 加padding或border, 浮动, 绝对定位等), 则div.b3的margin-top有效.

  3. 如果没有div.flo, 则div.b3的margin-top有效, 尽管会发生margin collapsing.

以上三个情况在熟悉了BFC和margin collapsing之后都好理解.

而这个在线演示的奇怪之处就在于它引入了clearance和margin collapsing, 我不明白的地方就是这两个效果共同作用的机理 . 我看了W3C上 clearance 和margin collapsing的内容, 然而并没有搞清原因.

stackoverflow上有几个一样的问题(其中有一个问题长达五年之久, 始于10年, 五年后的现在, 答案排在第一的作者虽然给出了解决办法, 但也坦言仍然没搞清楚原理), 可惜回答都没有满意的.

代码如下:

HTML:


 <section style="height: 20px;">
</section>
<section>
  <div class="flo"></div>
  <div class="b3"></div>
</section>
<p>The bottom margin of div.b3 collapses with this p element. But the top margin of b3 with clearance is mysteriously ignored.</p>

CSS:


 body {
  font-family: "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
  color: #fff;
}

section {
  background: purple;
  margin-top: 20px;
}

.flo {
  width: 150px;
  background: pink;
  border: 5px dashed #ff9e2c;
  float: left;
}

.b3 {
  width: 100px;
  height: 100px;
  border: 8px solid lightgreen;
  background: #4e97cd;
  margin: 1000px 0 20px 0;
  clear: both;
}

p {
  background: #6AC5AC;
  margin: 15px 0;
}

浮动 css 清除浮动 collapsing-margins float

mascot 9 years, 5 months ago

我想或许用F12看一下section的浏览器默认样式或许有发现

rosette answered 9 years, 5 months ago

margin-top会作用到父容器上,
margin用来处理同级元素

MEKY君 answered 9 years, 5 months ago

我之前貌似也遇到过同样问题,但因为什么忘记了,反正就是因为 clear 引起的。给父级加上 overflow: hidden; 就解决了。

菊部地区有血 answered 9 years, 5 months ago

  1. 如果没有包裹的 section,b3 上外边距同第一个 section 的下外边距属于相邻关系,故折叠

  2. 建立新BFC的元素的外边距不同其在文档流内子元素外边距折叠,因为二者不在一个块格式化上下文,父盒在父盒自己所在的,子盒在父盒创建的。故题主第二情况折叠

  3. 没有 flo 时候,b3 不需空隙生成,包裹 section 和 b3 属相邻关系,故折叠

  4. 凡生成了空隙,则外边距必不折叠。然而空隙可为负值,故再高的外边距遇到空隙,尽管不折叠,仍然像是被吞了一样。故@cool_zjy所言欠妥

详细可见鄙人所译CSS规范。

http://segmentfault.com/a/1190000003099116#articleHeader3
http://segmentfault.com/a/1190000003096320#articleHeader5

kaorisa answered 9 years, 5 months ago

我只想说,这和margin collapse有什么关系?
之所以不生效是因为margin只会对普通文档流的元素产生计算,其相邻的float元素已经脱离了文档流,自然没有作用。

pluto answered 9 years, 5 months ago

清除浮动的clear:both不要用在b3上,用在b3上的话,再b3后面的元素才是清除浮动后的有效显示

你可以在flo和b3间添加一个<div style="clear:both"></div>来清除浮动

不用把清浮动和其他样式混着一起用

前方高能量反应 answered 9 years, 5 months ago

仔细研究了 W3C 文档中 关于 clear 的部分 ,简单谈谈自己的理解。
先说自己的结论:
设置 clear 非 none 的元素的 margin-top 是否生效,主要取决于这个 margin-top 能否推动该元素越过所有 float 元素的。

其实很简单,可以参考下面代码:


 <div style="float:left; background-color: #eee; height:20px; width:100px;"></div>
<div style="height: 10px;"></div>
<div style="clear:both; background-color: #aaa; margin-top:10px;">clear</div>

这里我们改变第三个 div 的 margin-top,可以看到:当 margin-top<10px 时,margin-top 不会表现,而被 clear 创建的间隙替代;当 margin-top>=10px 时,margin-top 才表现出来。

放到题主的例子中,虽然设置了 1000px 的 margin-top,但 margin-top 被折叠成为父元素的 margin-top,div.b3 根本没有 margin-top,不能将 div.b3 推动越过 div.flo 元素底部,因此该 margin-top 就被废掉了,而由浏览器生成间隙来将 div.b3 推动越过 div.flo(关于间隙如何生成请参见 W3C 的文档,有非常详细的描述)。

同时,也非常容易理解为什么 section 设置 overflow:hidden 触发 BFC 后 margin-top 随之生效。这时 margin collapse 被禁用,div.b3 实实在在拥有了 margin-top,同时这个 margin-top 足以推动其越过 div.flo,因此 margin-top 便生效了。

不足之处欢迎补充讨论。

xyaa01 answered 9 years, 5 months ago

Your Answer