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;
}
一年后回来看这个问题,从@HaoyCn的回答里得到了灵感,让我重新读clearance,发现答案其实就在那。
关于clearance(间隙)
这一部分分析为什么
div.b3
顶部的margin
无论如何增大,div.b3
都保持在div.flo
的下方位置而不改变。上述规范告诉我们, 当
clear
属性不是none
的时候,hypothetical position
顶部border
的边缘没有低于对应的浮动元素底部外边缘(bottom margin)的时候,clearance
就会出现。那么
clearance
有多少呢?上述规范说了取两种情况下计算结果的最大值。就本例而言:
假设:
section
的顶部border
边缘为纵坐标0。div.b3
的顶部margin
是M2,div.flo
高度为H(含外边距)。第一种情况的clearance
为C1,第二种情况的clearance
为C2。第一种情况的
clearance
说的是把div.b3
的border
边缘放在与div.flo
底部外边缘平齐的位置所需要的必要数量。按照上述计算规则,当clearance
出现的时候section
的margin
和div.b3
的margin
不会collapse
(具体见第二部分)第二种情况的
clearance
说的是把div.b3
上边缘放在hypothetical position
(也就是clear
为none
的时候)所需的必要数量。取两者最大值为
-900px
,即为clearance
的大小。所以div.b3
的border
上边缘始终会在div.flo
底部外边缘的下方,但由于上述的计算规则,尤其注意第二种情况下div.b3
不会因为顶部margin
增加而改变位置。关于margin collapsing
这一部分分析为什么
div.b3
的顶部margin
不与section
的顶部margin
发生collapse
。现在
clearance
处在section
的顶部margin
和div.b3
的顶部margin
之间,根据collapsing-margins的规定,section
和div.b3
这两margin
不会collapse,相关规范的细节如下:本例中的情况适用于上述两种相邻关系(adjoining)。
vertically-adjacent
虽然满足,但no clearance
这一条不满足,所以不会发生margin collapse。当然规范在
Note
里同样以更通俗的语言提到了这一点:注意: 这里
div.flo
不属于in-flow
,所以section
的first in-flow child
是div.b3
。