日期:2014-05-17  浏览次数:21068 次

【分享】说说标准 —— 揭开外边距折叠(Collapsing margins)的面纱
生活本不是华袍,更禁不住揭开来看。 ——美丽的xixi
生活之美,在于真实和朦胧之间。本没有想象中美丽,却又有许多人非要揭示它的艰辛。
虽说,生活上的事,不须太过清楚,要深得“难得糊涂”其中三味,但工作上的事,确实越清楚越好,仔细想想,原来是因为工作比生活简单的多的多。

今天,我正要当众揭开外边距折叠的面纱。哇咔咔咔咔!!!
外边距折叠,是属于盒模型部分的一个重要概念,之所以要把它拿出来说,一是放到一起内容太多,二是这涉及到元素和元素之间的关系,不再是单纯的单个元素形成的矩形框,所以我觉得单独讲比较合适。此篇可结合 【分享】说说标准 ---- 你真的了解盒子模型(box model)吗? 来看。

我对此概念的了解,要从很久很久以前说起。
很久很久以前,我刚刚开始接触CSS的时候,对外边距折叠的认识,只有一句话:垂直方向上相邻的两个外边距(margin)会合并成一个,最终的大小,是两个中较大的。什么是外边距折叠,以及还有其他什么情况下会发生,都不清楚。
不知道,各位童鞋所认识的外边距折叠又是怎样的呢?
后来,在实际应用中发现,外边距折叠不是这么简单的,其中包含了很多其他情况下的折叠规则。
于是乎,就仔细的查询了一下相关内容。依然是来自W3C CSS2.1 8.3.1

目录:
一、概念
二、margin折叠的规则
1. 两个或多个毗邻的普通流中的块元素垂直方向上的margin会折叠
2. 浮动元素/inline-block的元素/绝对定位元素的margin不会和垂直方向上的其他元素的margin折叠
3. 创建了块级格式化内容的元素,不和它的子元素发生margin折叠
4. 元素自身的margin-bottom和margin-top相邻时也会折叠

一、概念
Collapsing margin,指的是毗邻的两个或多个外边距 (margin) 会合并成一个外边距,即外边距折叠。
其中所说的 margin 毗邻,可以归结为以下两点:
  1. 这两个或多个外边距没有被非空内容、padding、border或clear分隔开。
  2. 这些margin都处于普通流(in-flow,非浮动元素,非定位元素)中。

二、margin折叠的规则
1. 两个或多个毗邻的普通流中的块元素垂直方向上的margin会折叠
A. 两个或多个
说明其数量必须是大于一个,又说明,折叠是元素与元素间相互的行为,不存在A和B折叠,B没有和A折叠的现象了。
B. 毗邻
是指没有被非空内容、padding、border或clear分隔开,说明其位置关系。
注意一点,在没有被分隔开的情况下,一个元素margin-top会和它普通流中的第一个子元素(非浮动元素等)的margin-top相邻;只有在一个元素的height是”auto”的情况下,它的margin-bottom才会和它普通流中的最后一个子元素(非浮动元素等)的margin-bottom相邻。
文章不够,例子来凑:
HTML code
<div style="border:1px solid red; width:100px;">
    <div style="margin:50px 0; background-color:green; height:50px; width:50px;">
       <div style="margin:20px 0;">
           <div style="margin:100px 0;">B</div>
       </div>
    </div>
</div>
浏览器截图:

以上测试用例中,margin会把B的包含块撑开。
如果一个元素的height特性的值不是 auto,那么它的margin-bottom和它的子元素的margin-bottom不算是相邻,因此,不会发生折叠。
margin-top 没有此限制,所以是 100px,margin-bottom 没有折叠,所以只有 50px。

C. 垂直方向
是指具体的方位,只有垂直方向的margin才会折叠,也就是说,水平方向的margin不会发生折叠的现象。

D. 折叠后margin的计算
参与折叠的margin都是正值
例:
HTML code
<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都是正数的情况下,会取其中margin较大的值为最终 margin值。

参与折叠的margin中有正值,有负值
如果,毗邻的margin中有正值,同时存在负值会怎样呢?有正有负,先取出负margin中绝对值最大的,然后,和正marin值最大的magin,相加。
请看下面的例子:
HTML code
<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位置,负向位移。
看例子:
HTML code
<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>
截图: