为什么给一个元素设置清除浮动后margin-top无效? (该元素和其前面的浮动元素有一个包裹层)
codepen在线演示:
http://codepen.io/medifle/pen/qdwpje
div.flo是左浮动元素, div.b3清除了浮动, 其margin-top却被忽略掉了. 注意这两个元素由一个section元素包裹.
下面是我观察到的一些情况:
-
如果没有这个section包裹, 则div.b3的margin-top有效.
-
如果给这个包裹用的section元素用任何防止 margin collapsing 的方法(比如说设置'overflow: hidden;', 加padding或border, 浮动, 绝对定位等), 则div.b3的margin-top有效.
-
如果没有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
Answers
-
如果没有包裹的 section,b3 上外边距同第一个 section 的下外边距属于相邻关系,故折叠
-
建立新BFC的元素的外边距不同其在文档流内子元素外边距折叠,因为二者不在一个块格式化上下文,父盒在父盒自己所在的,子盒在父盒创建的。故题主第二情况折叠
-
没有 flo 时候,b3 不需空隙生成,包裹 section 和 b3 属相邻关系,故折叠
-
凡生成了空隙,则外边距必不折叠。然而空隙可为负值,故再高的外边距遇到空隙,尽管不折叠,仍然像是被吞了一样。故@cool_zjy所言欠妥
详细可见鄙人所译CSS规范。
http://segmentfault.com/a/1190000003099116#articleHeader3
http://segmentfault.com/a/1190000003096320#articleHeader5
仔细研究了 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 便生效了。
不足之处欢迎补充讨论。