译自:
外边距折叠是CSS布局中很小的一个知识点,但是却能够对我们的页面布局产生很大的影响。这篇文章详细介绍了外边距折叠的情况及如何避免,希望能够帮助大家加深理解。水平有限,翻译不当还请指正。
~文章内容略显啰嗦,可以重点关注代码部分~让我们来探究一下外边距折叠的结果是什么,它将怎样影响页面上的元素。
是这样定义外边距折叠的:
In this specification, the expression collapsing margins means that adjoining margins (no non-empty content, padding, or border areas, or clearance separate them) of two or more boxes (which may be next to one another or nested) combine to form a single margin.
简单说,这个定义表明当垂直方向两个元素的外边距(译:即margin
)相接触时,只有margin
值较大的会被选用,而margin
较小的元素的外边距会被折叠为0。在其中一个元素的margin
为负值的情况下,两元素的外边距是两者求和。如果两个元素的外边距都是负值,那么取较小的负值作为最终外边距(如-3px,-5px,取-5px)。这个定义适用于相邻或嵌套的元素上。
- 浮动元素
- 绝对定位元素
- 行内块元素
- 设置了
overflow
不为visible
的元素(不会与其子元素发生外边距折叠) cleared
元素(上外边距不会与其父块的下外边距折叠。译:此处不太理解,原文是They do not collapse their top margins with their parent block’s bottom margin.)- 根元素
这是一个很难理解的概念,让我们来看一些例子。
相邻元素间的外边界折叠
相邻元素的外边距折叠。简言之,就是文档流(译:normal document flow,国内常译为文档流)中垂直方向相邻的块级元素,只有margin
值最大的元素的外边距会被采用,而margin
较小的元素的外边距会被折叠为0。例如,如果一个元素的margin-bottom
为25px
,在其下方相邻的元素的margin-top
为20px
,那么只有25px
的下外边距会被应用,即两元素间的距离为25px
,而不是45px
(25+20)。
h1 { margin: 0 0 25px 0; background: #cfc;}p { margin: 20px 0 0 0; background: #cf9;}
如图1所示,两个元素间的间隙只有25px
,较小的外边距被折叠为0。如果上述例子中元素的外边距相等(如,都是20像素),那么两元素间的距离就只是20px
。
h1 { margin: 0 0 25px 0; background: #cfc;}p { margin: -20px 0 0 0; background: #cf9;}
h1
元素的下外边距是一个正数(25px
),p
元素的上外边距是一个负数(-20px
),在这种情况下,这两个值将进行求和计算得到最终的间距:25px
+ (-20px
) = 5px
。
父子元素间的外边距折叠
目前为止,我们只讨论了相邻元素间的外边距折叠,但同样的情况适用于外边界接触的父子元素间。这里的接触是指在相邻的margin
之间没有padding
,border
和content
。在下面的例子中,一个父元素包含了一个被设置了上外边距的子元素:
h1 { margin: 0; background: #cff;}div { margin: 40px 0 25px 0; background: #cfc;}p { margin: 20px 0 0 0; background: #cf9;}
在上边的样式表中,为p
元素声明了一个上外边距,在下边的代码中可以看到p
元素是div
元素的子元素。
Heading Content
Paragraph content
图2中可以看到这段代码的结果:
你可能会认为p
元素和h1
元素的间距为60px
,因为div
元素的margin-top
是40px
,并且p
元素的margin-top
为20px
。你或许也会认为在p
元素的上方会有20px
的范围展示div
元素的背景色。但是如图所示,并非如此,因为发生了外边距折叠,导致只有最大的外边距被应用(和相邻块一样)。
div
元素没有上外边距(译:即margin-top
为0)并且p
元素的margin-top
为40px
我们会得到相同的结果。p
元素的40px
上外边距转化成div
元素的上外边距,将div
元素下移40px
,并使p
元素紧贴div
顶部。在div
元素内p
元素的上方不会有背景色展示。 为了使两个元素的外边距都展示,并且使div
的背景色展示在p
元素的上方,这里需要设置一个border
或者padding
去阻止外边距折叠。我们简单的为div
元素添加一个上边框,就可以得到最初期待的效果: h1 { margin: 0; background: #cff;}div { margin: 40px 0 25px 0; background: #cfc; border-top: 1px solid #000;}p { margin: 20px 0 0 0; background: #cf9;}
在图3中,我们可以看到div
元素与h1
元素的距离依旧是40px
,但是p
元素被下移了20px
的距离,因此显示了20px
范围的div
背景色(通过设置外边框)。
如果我们不希望在设计上展示可见的上边框,1px
的上内边距会产生同样的效果。记住border
和padding
应该应用在父div
上,在p
元素上不会阻止外边距折叠,因为p
元素的margin
在border
的外面。
div
元素,每一个都设置了10px
的外边距。每个div
都设置了不同的背景色,所以我们可以清楚的看到外边距折叠的效果: .box { margin: 10px;}.a { background: #777;}.b { background: #999;}.c { background: #bbb;}.d { background: #ddd;}.e { background: #fff;}
图4展示了上述 CSS 的结果。
正如这个例子所示,这段CSS的效果是引人注目的:所有的垂直方向外边距折叠为一个单独的,10px
的外边距。不同于水平方向所示的每个外边距都可见,虽然我们为每个元素设置了不同的背景色,但垂直方向并没有展示类似的颜色。整个块将会被放置在距文档流中其他元素10px
的位置上,所有嵌套的块的外边距将会折叠成一个。
10px
,可以通过简单的设置一个9px
的margin
和1px
的padding
来实现: .box { margin: 9px; padding: 1px;}
微小的改动会阻止垂直方向上的外边距折叠,效果图5所示。
当然,考虑IE的兼容性是很重要的。第一个例子(图4)中的元素在IE中会直接展示位图5的效果。另外值得一提的是在IE之外的其他浏览器中,设置overflow
为不等于visible
的其他值时会产生同样的效果。
总结
尽管外边距折叠给人的第一印象不够直观,但它确实使得多层元素嵌套的情况更加简单,也更令人满意。如果有需要你也可以使用上述简单方式阻止外边距折叠。
那么,现在你真的读懂外边距折叠了吗?不如我们来做个小小的测试吧。对A,B,C三个块级元素分别设置margin
如下图所示,请问:
- 把B和C同时放到A中,BC间距是多少?
- 基于问题1,把B的
margin
改为-30px
呢? - 基于问题1,把BC的
margin
均取负数呢? - 把B放入A内,C放入B内时,ABC的位置是怎样的?
- 基于问题4,B的
margin
为-30px
呢?
实践出真知,不确定答案的同学还是亲自动手试试吧:)