代码改变世界

外边距折叠

2012-08-21 16:44  youxin  阅读(412)  评论(0编辑  收藏  举报

在CSS中,当一个元素的上或下外边距正好和另外一个元素的上或下外边距接触时就会产生外边距折叠。这个概念很简单:两个外边距中更小的那个减小为零。如果两个元素的外边距具有相同的长度,那么其中一个被减小为零。外边距折叠在图7-9中进行示范。

<div id="top"> </div>
<div id="bottom"></div>

注意:第一个divmargin-top还是10px,只是下面的没有了。

一个元素被另外一个元素包含在里面时也会发生外边距折叠。两个外边距在什么地方接触是无关紧要的,如果两个外边距接触,那么即使是另一个元素里面的元素也会和它的父元素发生外边距折叠。图7-10中显示了一个这样的例子。

<div id="parent">
<div id="child">
</div>
</div>

显示了外边距折叠在父子元素之间是如何发生作用的。如果一个子元素的外边距直接接触到父元素的外边距,那么就会发生外边距折叠。就像图7-9中相邻同属外边距折叠一样,较大的外边距是胜利者。胜利的外边距总是应用到父元素,子元素的外边距总是被折叠。因此,如果可以防止两个外边距相互接触,那么外边距折叠就可以避免。可以通过对父元素使用内边距或者边框来防止两个外边距相互接触 。

在父元素增加:

border:1px solid blue;

 

在margin都是正数的情况下,会取其中margin较大的值为最终 margin值。

参与折叠的margin中有正值,有负值。如果,毗邻的margin中有正值,同时存在负值会怎样呢?有正有负,先取出负margin中绝对值最大的,然后,和正marin值最大的magin,相加。请看下面的例子:

<div style="height:50px; margin-bottom:-50px; width:50px; background-color: red;">A</div> 
<div style="height:50px; margin-top:100px; width:50px; background-color: green;">B</div> 

面的例子最终的margin是 100+(-50)=50px。

参与折叠的margin都是负值。最后,如果毗邻的两个margin都是负值又会怎样呢?当margin都是负值的时候,取的是其中绝对值较大的,然后,从0位置,负向位移。看例子:

<div style="height:100px; margin-bottom:-75px; width:100px; background-color: red;">A</div> 
<div style="height:100px; margin-left:50px; margin-top:-50px; width:100px; background-color: green;">B</div>

相邻的margin要一起参与计算,不得分步计算。以上举的例子都是兄弟节点在垂直方向的相邻,要注意,相邻的元素不一定非要是兄弟节点,父子节点也可以,即使不是兄弟父子节点也可以相邻。举一个复杂点儿的例子,我们要计算的是A和B之间的margin最终应该是多少:

<div style="margin:50px 0; background-color:green; width:50px;"> 
    <div style="margin:-60px 0;"> 
           <div style="margin:150px 0;">A</div> 
    </div> 
</div> 
<div style="margin:-100px 0; background-color:green; width:50px;"> 
    <div style="margin:-120px 0;"> 
           <div style="margin:200px 0;">B</div> 
    </div> 
</div> 

 

有人可能说了,算A和B之间的margin,分别算A和其父元素的折叠,然后与其父元素的父元素的折叠,这个值算出来之后,应该是90px。依此法算出B的为80px;然后,A和B折叠,margin 为90px。

对吗?错了,大错特错。错在哪里了呢?请注意,多个margin相邻折叠成一个margin,所以计算的时候,应该取所有相关的值,而不能分开,分步来算。以上例子中,A和B之间的margin折叠产生的margin,是6个相邻margin折叠的结果。分别是:

◆正值:50px,150px,200px

◆负值:-60px,-100px,-120px

根据有正有负时的计算规则,正值的最大值为 200px,负值中绝对值最大的是-120px,所以,最终折叠后的margin应该是 200 + (-120) = 80px。
可以打开浏览器来验证自己的猜想。

2. 浮动元素/inline-block的元素/绝对定位元素的margin不会和垂直方向上的其他元素的margin折叠

浮动元素的margin在垂直方向上也不会发生 margin折叠,即使和它相邻的子元素,也不会。看例子:

<div style="margin-bottom:50px; width:50px; height:50px; background-color:green;">A</div> 
<div style="margin-top:50px; width:100px; height:100px; background-color:green; float:left;"> 
    <div style="margin-top:50px; background-color:gold;">B</div> 
</div> 

可见,两个绿色的块儿之间,相距100px,而若B和它的浮动包含块发生margin折叠的话,金色的条应该位于绿色块的最上方,显然,没有发生折叠。
将float:leftt分别换成 “display:inline-block”和”position:absolute”测试后两种情况,截图与上同。

3. 创建了块级格式化内容的元素,不和它的子元素发生margin折叠 (这点值得注意,)

关于块级格式化内容,请参照:http://www.w3.org/TR/CSS2/visuren.html#block-formatting,其中浮动元素,绝对定位元素,以及 overflow值不是’visible’的元素,都符合。以 “overflow:hidden” 的元素为例:

  1. <div style="margin-top:50px; width:100px; height:100px; background-color:green; overflow:hidden;"> 
  2.     <div style="margin-top:50px; background-color:gold;">B</div> 
  3. </div>

 

 

 

若B和它的 “overflow:hidden” 包含块发生margin折叠的话,金色的条应该位于绿色块的最上方,显然,没有发生折叠。

 

4. 元素自身的margin-bottom和margin-top相邻时也会折叠

 

自身margin-bottom和margin-top相邻,只能是自身内容为空,垂直方向上border、padding为0。例:

  1. <div style="border:1px solid red; width:100px;"> 
  2.     <div style="margin-top:100px;margin-bottom:50px;"></div> 
  3. </div>

以上代码运行后,我们得到的是一个正方形,说明,最终的margin是100px,而不是150px,也就是说发生了margin折叠。

参考:http://developer.51cto.com/art/201008/219288.htm

 

 

 深入:

http://www.w3.org/TR/CSS2/box.html

http://reference.sitepoint.com/css/collapsingmargins

 

http://www.howtocreate.co.uk/tutorials/css/margincollapsing

 

http://www.w3help.org/zh-cn/kb/006/ 非常好