为什么这个CSS的margin-top样式不起作用?

425

我试图在一个嵌套的

中添加margin值。除了顶部值似乎被忽略外,一切都正常。但是为什么呢?

我的期望:
What I expected with margin:50px 50px 50px 50px;

实际效果:
What I get with margin:50px 50px 50px 50px;

代码:

#outer {
  width: 500px;
  height: 200px;
  background: #FFCCCC;
  margin: 50px auto 0 auto;
  display: block;
}

#inner {
  background: #FFCC33;
  margin: 50px 50px 50px 50px;
  padding: 10px;
  display: block;
}
<div id="outer">
  <div id="inner">
    Hello world!
  </div>
</div>

W3Schools没有解释为什么margin会以这种方式行为。


5
你尝试过让内部的浮动吗? - Rooster
9
嗯,使用“float:left;”就可以了...但为什么需要这样做呢?我不想让它浮动。而且为什么左/右边距有效呢? - lejahmie
69
欢迎来到 CSS 外边距折叠算法的有趣世界! - GordonM
3
你什么都不知道,琼·雪。 - lejahmie
4
我记不得 CSS 何时变得如此复杂了。它只是用于显示元素,但我看到许多人在与它斗争。学习它并不像你可以轻松掌握,而是需要“研究”它。 - Jonny
显示剩余3条评论
14个回答

545
你实际上看到的是 #inner 元素的顶部边距 collapse 合并到 #outer 元素的顶部边缘,只留下了 #outer 边距(尽管在你的图像中没有显示)。两个框的顶部边缘相互贴合,因为它们的边距相等。
以下是W3C规范中相关的要点:

8.3.1 折叠边距

CSS中,两个或多个盒子(可能是兄弟,也可能不是)的相邻边距可以组合成一个单一的边距。以这种方式组合的边距被称为折叠边距

相邻垂直边距折叠 [...]

如果且仅当以下条件成立时,两个外边距相邻:

  • 两者均属于参与同一块级格式化上下文的内联块级框
  • 没有行框、清除、填充和边框将它们分隔开来
  • 两者属于垂直相邻的框边缘,即形成以下一种对之一:
    • 一个框的上外边距和其第一个内联子元素的上外边距

为了防止外边距折叠,可以执行以下任何操作之一:

以上选项可防止外边距折叠的原因是:

  • 浮动框与其他框之间的外边距不会折叠(即使在浮动框和其内部流元素之间也不会)。
  • 建立新块级格式上下文的元素的外边距(如浮动元素和具有'overflow'属性但非'visible'值的元素)不会与其内部流元素折叠。
  • 内联块级框的外边距不会折叠(即使与其内部流元素也不会)。

左右外边距的表现符合您的预期,因为:

水平外边距永远不会折叠。


21
显然,您不是唯一一个认为这很愚蠢的人。 - BoltClock
2
这个答案非常棒!只是想补充一点。你引用了w3c的话,但我现在才意识到。所以为了让其他人清楚,你也可以给#outer加上边框。 - driechel
我知道 - 只是想让您知道。因为您启用了♦,所以我想您可能希望恢复评论或相应地更改帖子。顺便说一句,感谢您提供的好答案。 - E.P.
border-top/bottom:1px solid transparent (or whatever your bg color) 是在解决这个问题时的另一个常用方法 8-) - Frank N
我猜在很久以前添加这个功能时可能有道理,但事后看来,这是一个非常愚蠢的想法。浪费在处理这个问题上的开发时间一定是巨大的。 - Cesar Varela
显示剩余3条评论

131

尝试在内部 div 上使用 display: inline-block;。 就像这样:

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:block;
}
#inner {
    background:#FFCC33;
    margin:50px 50px 50px 50px;
    padding:10px;
    display:inline-block;
}

13
好的回答。如果能解释为什么这种变化可以解决问题会更好。 - JohnFx
2
好的,这太奇怪了!为什么会有效呢?为什么它不像预期的那样工作的逻辑解释是什么?margin-left/right可以不用“display:inline-block;”也能工作。但是使用“display:inline-block;”时需要注意的是,您将失去div的100%宽度设置。 - lejahmie
7
将它切换为"inline-block"会强制浏览器在放置该div并应用其他规则后重新评估其大小。 - Rooster
尝试了一下,结果出现了阶梯效应。 - Jonny
这真是太神奇了!!!2012年的答案救了我!! - Adriana Hernández

33

BoltClock的答案非常扎实。在此,我想为这个问题添加几个解决方案。 请查看w3c_collapsing margin。绿色部分是可能解决此问题的思路。

解决方案1

浮动框与任何其他框之间的边距不会折叠(甚至不会在浮动框和其流内子元素之间折叠)。

这意味着我可以将float:left添加到#outer#innerdemo1

还要注意,float会使margin中的auto无效。

解决方案2

建立新块格式化上下文的元素的边距(例如浮动元素和具有“overflow”而不是“visible”的元素)不会与其流内子元素折叠。

除了visible之外,让我们把overflow: hidden放到#outer中。这种方式似乎相当简单和不错。我喜欢它。

#outer{
    width: 500px;
    height: 200px;
    background: #FFCCCC;
    margin: 50px auto;
    overflow: hidden;
}
#inner {
    background: #FFCC33;
    height: 50px;
    margin: 50px;
}

解决方案3

绝对定位的盒子的边距不会折叠(即使是它们的内部流动子元素也不会折叠)。

#outer{
    width: 500px;
    height: 200px;
    background: #FFCCCC;
    margin: 50px auto;
    position: absolute; 
}
#inner{
    background: #FFCC33;
    height: 50px;
    margin: 50px;
}

或者

#outer{
    width: 500px;
    height: 200px;
    background: #FFCCCC;
    margin: 50px auto;
    position: relative; 
}
#inner {
    background: #FFCC33;
    height: 50px;
    margin: 50px;
    position: absolute;
}

这两种方法将打破

的正常流程

解决方案4

行内块框的外边距不会塌陷(即使是其内部流对象也不会)。

与Enderskill相同

解决方案5

一个内部流块级元素的底部外边距总是与下一个内部流块级兄弟元素的顶部外边距合并,除非该兄弟元素具有clearance属性。

这与问题没有太多关系,因为它是兄弟元素之间塌陷的外边距。通常意味着如果顶部框具有margin-bottom: 30px,而其兄弟框具有margin-top: 10px。它们之间的总外边距为30px,而不是40px

解决方案6

如果一个内部流块元素没有顶部边框、没有顶部填充且子元素没有clearance属性,则其顶部外边距将与其第一个内部流块级子元素的顶部外边距合并。

这非常有趣,我只能添加一行顶部边框线

#outer{
    width: 500px;
    height: 200px;
    background: #FFCCCC;
    margin: 50px auto;
    border-top: 1px solid red;
    
}
#inner {
    background: #FFCC33;
    height: 50px;
    margin: 50px;
    
}

此外,<div> 默认是块级元素,因此您不必特意声明它。很抱歉由于我的新手声望,我无法发布超过2个链接和图像。至少下次您看到类似的问题时,知道问题出在哪里了。

23

我不确定您的内容为什么无法正常工作,但您可以在外部div中添加overflow: auto;


有很多不同的解决方案可以解决这个问题。谢谢!这个答案结合@BoltClock的答案提供了关于为什么这个解决方案有效的好信息。 - lejahmie

20

不太确定原因,但将内部CSS更改为

display: inline-block;

看起来有效。


16
如果您向#outer添加任何padding,它将起作用。此处为演示:

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:block;
    padding-top:1px;
}
#inner {
    background:#FFCC33;
    margin:50px 50px 50px 50px;
    padding:10px;
    display:block;
}
<div id="outer">
    <div id="inner">
        Hello world!
    </div>
</div>


5

创建新的块级格式化上下文

你可以在父元素上使用display: flow-root,它会创建新的块级格式化上下文从而防止外部元素的margin折叠。

将overflow属性的值改为auto或者使用flexbox也会产生同样的效果。

https://codepen.io/rachelandrew/pen/VJXjEp


5

虽然没有解释为什么会出现这种情况(很可能与margin折叠有关),但是最简单/最合理的方法似乎是只要在外部div中添加padding-top即可实现你想要做的事情:

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    padding-top: 50px;
}
#inner {
    background:#FFCC33;
    margin:0px 50px 50px 50px;
    padding:10px;
}
<div id="outer">
    <div id="inner">
        Hello world!
    </div>
</div>

小提示 - 如果代码中没有其他内容阻止它成为块级元素,那么将div设置为 display:block; 是不必要的。


4

试试这个:

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:table;
}
#inner {
    background:#FFCC33;
    margin:50px 50px 50px 50px;
    padding:10px;
    display:block;
}
<div id="outer">
    <div id="inner">
        Hello world!
    </div>
</div>

祝你好运!


3

使用padding-top:50px为外部div添加内边距。类似这样:

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:table;}

注意:填充会增加你的 div 的大小。在这种情况下,如果你的 div 大小很重要,也就是说,如果它必须具有特定的高度,请将高度减少 50px。
#outer {
    width:500px; 
    height:150px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:table;}

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