嵌套的垂直外边距折叠是如何工作的?

8

我很难理解嵌套元素中的垂直边距折叠概念。我看了一篇文章在http://www.howtocreate.co.uk/tutorials/css/margincollapsing上,它解释了如何工作,但是我仍然感到困惑。在该文章的示例中,它引用了以下两个元素:

<div style="margin-top:10px">
<div style="margin-top:20px">
A
</div>
</div>  

由于内部div有20像素的外边距,这个外边距将应用于整个代码块。令我困惑的是之后的一切,还没有考虑与Internet Explorer 7的问题。是否有人能够以简单的方式向CSS的新手解释一下?


你是指蓝色div中的段落部分吗? - BoltClock
1
我不确定我能比那篇文章更好地解释。也许用一些精美绘制的图片呢? - thirtydot
@BoltClock - 除了我提到的内部块占优势之外,Nested margins下的所有内容。 - PeanutsMonkey
3个回答

13

需要记住的两个规则:

  1. 如果边距相接触,则它们会折叠。
  2. 嵌套项目只有在边距分隔它们时才会“紧贴”。
  3. "Flow"之外的元素行为不同。也就是说,这种行为并不适用于浮动、position:fixed或position:absolute元素。

所以对于这个HTML(嵌套的div):

<div id="outer"> 
    <div id="inner">
        A
    </div>
</div> 

同时,这是初始的CSS:

#outer {
    margin-top:10px;
    background:blue;
    height: 100px;
}
#inner {
    margin-top:20px;
    background:red;
    height: 33%;   
    width: 33%;
}

边距会折叠到相邻边距和嵌套的div上,如下所示:“snuggles” div贴在容器的开头,就像这样:(在jsFiddle中查看)
Nested margin collapse但是,一旦两个边距被分隔开——例如通过边框或容器中的前置内容——边距不再接触,因此它们不再折叠。例如,只有一个小的、不可打断的空格,如下所示:
<div id="outer">&nbsp;
    <div id="inner">
        A
    </div>
</div>

解决margin重叠问题:(请参考jsFiddle)
嵌套margin不会重叠

使用边框代替文本来避免重叠问题:(请参考Fiddle)
无重叠,有边框


谢谢。当你说“容器中的前置内容”时,你确切指的是什么?我也理解如果前置容器(例如下面示例中嵌套div中的父div)有边框或填充,它也会“破坏”垂直折叠。是这样吗?<div id="parent"><div id="child1">content</div><div id="child2">content</div> - PeanutsMonkey
1
“先前的内容”指的是除了折叠空格之外,在div#inner之前且在div#outer内的任何内容。在示例中,我使用了&nbsp;,但文本或其他节点也可以。是的,如果div#outer有边框或填充,则会分隔边距,从而破坏折叠。请参见更新后的答案。 - Brock Adams
当你说“折叠空格”时,你是指元素给出的高度吗?例如,如果我将“字体大小”定义为1em,则元素之间的高度或空白区域为1em吗? - PeanutsMonkey
1
不,大多数元素开头或结尾的空格会被折叠并且不可见。也就是说:浏览器将呈现<p>     Hello       </p><p>Hello</p>相同。对于<p> \n \r \t Hello</p>也是如此。只有特殊的、不间断的空格才不受此折叠影响。 - Brock Adams
好的。你有特殊的不换行空格的例子吗? - PeanutsMonkey
最常见的是&nbsp;实体。你也可以将其键入为字符代码160。(在Windows上,按住Alt键然后使用数字小键盘按下0160。) - Brock Adams

6

以下是一张图示:

Illustration of collapsing margins for nested divs

如果不太明显:蓝色=外部div,红色=内部div;我已经画出它们具有恒定的高度和水平位置。如果高度适合内容等,您可以计算出会发生什么。

"折叠前"列显示了如果边距不被视为相邻时所得到的结果,例如,如果您绘制蓝色/外部div的边框;但是如果没有边框,则会得到“折叠后”列。顶行将两个边距从示例中交换,因为我认为在这种情况下的行为更直观;底部显示了howtocreate的示例,并与顶部行保持一致。


谢谢Brian。我有几个问题。当你说你用恒定的高度和水平定位来绘制它们时,你具体是什么意思?当你还说不相邻时,这具体是什么意思?我的理解是相邻等于文档正常流程中出现的情况,即你有一个元素在另一个元素上方没有任何样式。 - PeanutsMonkey
@PeanutsMonkey:这是因为盒模型规定高度只包括 height,不考虑边距、边框或填充。 - BoltClock
@BoltClock - 你说的“因为盒模型规定高度只包括高度”是什么意思? - PeanutsMonkey
@PeanutsMonkey - 看起来你已经得到了大部分的答案,但为了确保:常量高度意味着设置 height: 100px(如果不这样做,则 div 将根据其中的文本和其他元素自然调整其高度)。这只是解释了图表,边距仍然以相同的方式工作。(高度属性不包括边距)。您可以通过在外部 div 上放置填充或在内部 div 上放置左边距来实现所示的水平定位,无论哪种方式都不会影响垂直边距的工作。 - Brian L
相邻边距是指如果您考虑垂直空间,并查看在折叠之前边距的位置,则外部div的边距会触碰内部div的边距。如果内部div之前有一些外部div中的内容,或者存在填充或边框,则这两个边距将不被视为相邻。 - Brian L
显示剩余2条评论

0
两个需要记住的规则: 如果边距相接触,它们会折叠。如果只有边距分隔它们,嵌套项会“紧贴”。在“流”之外的元素的行为不同。也就是说,这种行为不适用于浮动、position:fixed或position:absolute元素。 Brock Adams是正确的,但我还想补充一点,“overflow:hidden”也可以防止嵌套边距折叠。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接