【分享】说说标准 —— 揭开外边距折叠(Collapsing margins)的面纱

WebAdvocate 2010-07-12 04:18:59
加精
生活本不是华袍,更禁不住揭开来看。 ——美丽的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相邻。
文章不够,例子来凑:
<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都是正值
例:
<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,相加。
请看下面的例子:
<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” 的元素为例:
<div style="margin-top:50px; width:100px; height:100px; background-color:green; overflow:hidden;">
<div style="margin-top:50px; background-color:gold;">B</div>
</div>
截图:

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

4. 元素自身的margin-bottom和margin-top相邻时也会折叠
自身margin-bottom和margin-top相邻,只能是自身内容为空,垂直方向上border、padding为0。
例:
<div style="border:1px solid red; width:100px;">
<div style="margin-top:100px;margin-bottom:50px;"></div>
</div>
截图:

以上代码运行后,我们得到的是一个正方形,说明,最终的margin是100px,而不是150px,也就是说发生了margin折叠。
其他过于复杂的情况,感兴趣的同学可以自己去W3C 官方网站阅读:http://www.w3.org/TR/CSS2/box.html#collapsing-margins

这个也好长……

更多说说标准系列文章:
【分享】说说标准系列目录
...全文
3214 47 打赏 收藏 举报
写回复
47 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
liner_z 2011-11-09
真够专业的。明白了
  • 打赏
  • 举报
回复
xjinza 2011-09-09
学习了
  • 打赏
  • 举报
回复
xuelianxingqing 2010-11-15
顶一个,学习了
  • 打赏
  • 举报
回复
xuelianxingqing 2010-11-15
顶,不错,学习下
  • 打赏
  • 举报
回复
sunxing007 2010-08-05
看来水很深, 只敢稍微了解一下.
  • 打赏
  • 举报
回复
势孤取和 2010-07-17
支持下~
  • 打赏
  • 举报
回复
hexhero 2010-07-15
每天回帖即可获得10分可用分!
  • 打赏
  • 举报
回复
凤凰涅檠 2010-07-14
mark up
  • 打赏
  • 举报
回复
lwwit 2010-07-14
顶.............
  • 打赏
  • 举报
回复
clocke 2010-07-14
好像不错,谢谢。
  • 打赏
  • 举报
回复
xk029 2010-07-14
  • 打赏
  • 举报
回复
语过添情 2010-07-14
margin mark!
  • 打赏
  • 举报
回复
bikini2u 2010-07-14
经典呀!一语惊人呀!


Between persons of Tiny Bikini equal income there is no social sexy bikinis sale distinction except the distinction of Ed Hardy Bikini merit. Money is nothing;character,conduct,and Ralph Lauren Bikini capacity are everything.Instead of sexy bikinis all the workers being leveled down to low wage standards and all the Sinful Bikini rich leveled up to fashionbale income standards,everybody under a system of Lacoste Bikini equal incomes would find his or her own natural level.There would be great Designer Brands Bikini people and ordinary people and little Tiny Ed Hardy Bikini peolpe,but the great would always be those who had done great things,and never the Sexy Ralph Lauren Bikini idiot whose mother had spoiled them and whose father had girl bikini left a hunred thousand a year;and the little would be persons of Louis Vuitton Bikini small minds and mean characters,and not poor persons who had Chanel Bikini never had a chance.That is why idiots are always in favour of inequality of income(their only chance of eminence),and the Ed Hardy Swimsuit really great in favour of equality.
  • 打赏
  • 举报
回复
Joe-xXx 2010-07-13
学习了啊~~~辛苦的LZ
  • 打赏
  • 举报
回复
wo554006164 2010-07-13
不错。顶起
  • 打赏
  • 举报
回复
mochimo 2010-07-13
[Quote=引用 30 楼 dinosun 的回复:]

一、人类:
1.两个哥们,一个脾气很暴,不允许他人踏进自己周围五步,否则动手;另一个脾气更暴,不允许他人踏进自己周围十步,否则上脚。问:这两个哥们的安全距离是多少?

2.爷俩,脾气同以上的两个哥们,其中儿子属于脾气更暴的。问:爷俩出门,其他人和他们爷俩的安全距离是多少?

二、超人:
上边 1 和 2 的人类进化了,能感应到其他人的“安全距离”并不允许自己的安全举例与他人的安全距离……
[/Quote]

三、仙水忍:时常人格分裂,一个人格脾气很暴,不允许其它人格踏进自己周围五步,否则硬气枪;另一个脾气更暴,不允许他人人格踏进自己周围十步,否则裂脚紫炎弹。问:这哥们自己不没事儿抽风的安全距离是多少?
  • 打赏
  • 举报
回复
DinoSun 2010-07-13
一、人类:
1.两个哥们,一个脾气很暴,不允许他人踏进自己周围五步,否则动手;另一个脾气更暴,不允许他人踏进自己周围十步,否则上脚。问:这两个哥们的安全距离是多少?

2.爷俩,脾气同以上的两个哥们,其中儿子属于脾气更暴的。问:爷俩出门,其他人和他们爷俩的安全距离是多少?

二、超人:
上边 1 和 2 的人类进化了,能感应到其他人的“安全距离”并不允许自己的安全举例与他人的安全距离较差,否则……

三、……
编不下去了,楼下继续。
  • 打赏
  • 举报
回复
haozi311 2010-07-13
很好 很优秀 我很喜欢
  • 打赏
  • 举报
回复
gentleness8023 2010-07-13
辛苦了、、、
  • 打赏
  • 举报
回复
xiuyouxu 2010-07-13
  • 打赏
  • 举报
回复
加载更多回复(23)
相关推荐
发帖
跨浏览器开发

5005

社区成员

解读Web 标准、分析和讨论实际问题、推动网络标准化发展和跨浏览器开发进程,解决各种兼容性问题。
社区管理员
  • 跨浏览器开发社区
加入社区
帖子事件
创建了帖子
2010-07-12 04:18
社区公告
暂无公告