Margin-Top会将外部div向下推。

144
我在我的包装div中将标题div作为第一个元素,但是当我在标题div中的h1上添加顶部边距时,它会将整个标题div向下推。我意识到这种情况发生在页面上第一个可见元素应用顶部边距时。
以下是示例代码片段。谢谢!

My Header

div#header{
 width: 100%;
 background-color: #eee;
 position: relative;
}

div#header h1{
 text-align: center;
 width: 375px;
 height: 50px;
 margin: 50px auto;
 font-size: 220%;
 background: url('../../images/name_logo.png') no-repeat;
}
<div id="header">
 <h1>Title</h1>
 <ul id="navbar"></ul>
</div>

8个回答

214

31
“overflow:hidden” 对于90%的情况更为适用。 - vsync
1
为什么使用overflow:hidden会更好? - peterchon
5
@peterchon - 因为自动化可能会导致滚动条出现。 - vsync
3
不再起作用,@SW4在此链接中的答案更好。 - am05mhz
1
overflow: hiddenoverflow: auto可能会导致一些意想不到的副作用,其中一些你可能一开始并没有注意到。我发现将margin更改为padding可以解决问题,就像下面的答案建议的那样。虽然我仍然不明白整个问题为什么会发生。 - Gilad Barner
显示剩余2条评论

37
我没有确切的解释为什么会发生这种情况,但我已通过将top-margin更改为top-padding, 或将display: inline-block添加到元素样式来修复此问题。
编辑:这是我的理论
我有一种感觉,这与边距的合并有关。
来自W3C边距合并
在本规范中,“合并边距”表示两个或多个框(可能相邻或嵌套)的相邻边距(无非空内容、填充或边框区域或间隙分隔它们)组合成一个单一边距。
我的理论是,由于第一个元素紧挨着body,因此两个边距合并并应用于body:这迫使body的内容从应用的折叠边距以下开始,以符合盒模型
有时边距不会合并,在这种情况下可能值得尝试(参见合并边距)。
* floated elements
* absolutely positioned elements
* inline-block elements
* elements with overflow set to anything other than visible (They do not collapse margins with their children.)
* cleared elements (They do not collapse their top margins with their parent block’s bottom margin.)
* the root element

3
同时,在具有折叠边距的元素上添加填充或边框将使其不再折叠(对于内部元素)。 - Anonymous
这对我很有帮助 - 我的容器中有绝对定位的元素(一个下拉菜单),因此 overflow:auto 无法工作。 - mwilcox
display: flex 似乎也禁用了折叠边距。 - Sebastian Nielsen

19

以下是避免父子元素之间的外边距合并的几种方法,使用适合你其他样式的方式:

  • display设置为除block以外的其他值。
  • float设置为非none的其他值。
  • 移除外边距,改用padding。例如,如果您有margin-top: 10px,请改为padding-top: 10px;
  • 移除外边距,使用position (absoluterelative)与属性topbottom等。例如,如果您有margin-top: 10px,请改为position: relative; top: 10px;
  • 在外边距合并的一侧,向父元素添加paddingborder。边框可以是1像素且透明的。
  • overflow设置为除visible以外的其他值,应用于父元素

5
我知道这是一个老问题,我已经遇到过很多次了。问题在于所有的修复方法都是可能产生意想不到后果的hack。
首先,根本问题有一个简单的解释。由于margin collapsing的工作方式,如果容器内的第一个元素具有顶部margin,则该顶部margin会有效地应用于父容器本身。您可以通过执行以下操作来自行测试:
<div>
    <h1>Test</h1>
</div>

在调试器中打开它并悬停在div上。您会注意到,这个div实际上是放置在H1元素的顶部边距停止的地方。这种行为是浏览器的意图。
所以有一个简单的解决方法,而不必诉诸奇怪的黑客,因为这里的大多数帖子都这样做(没有侮辱的意思,这只是事实)- 简单地回到原始解释 - ...如果容器内的第一个元素有顶部间距... - 在此之后,您需要容器中的第一个元素没有具有顶部间距。好吧,但是如何在不添加与文档语义无关的元素的情况下做到这一点呢?
很容易! 伪元素! 您可以通过类或预定义的mixin来实现此目的。添加一个:before伪元素:
.top-margin-fix::before {   
    content: ' ';
    display: block;
    width: 100%;
    height: .0000001em;
}

使用以下标记示例,您可以修改div如下:

使用这个方法,你可以根据上面的标记示例来修改你的div:

<div class="top-margin-fix">
    <h1>Test</h1>
</div>

为什么这样做有效?

如果一个容器的第一个元素没有上边距,它将设置下一个元素的顶部边距的起始位置。通过添加一个:before伪元素,浏览器实际上会在您的第一个元素之前将一个非语义化的元素(换句话说,对于SEO有好处)添加到父容器中。

问:为什么要设置高度为 0.0000001em?

答:为了让浏览器将边距元素向下推。该高度实际上是零,但它仍然使您可以向父容器本身添加填充。由于其高度实际上是零,因此它不会影响容器的布局。太好了。

现在,您可以添加一个类(或更好地,在SASS / LESS中添加一个mixin!)来解决这个问题,而不是添加奇怪的显示样式,当您想要对元素进行其他操作时,这些样式会导致意外的后果,即有意消除元素的边距和/或用填充替换它,或者使用真正不打算解决此问题的奇怪位置/浮动样式。


2
.0000001em 在IE11中会被四舍五入为零,从而破坏你的修复。但当我将其更改为.01em时,它就可以工作了。 - Esger
1
我想.01em足以有效地为零。好观点。 另一方面,现在已经是2018年了,我们中的许多人很快就会放弃对IE11的支持,特别是最近宣布微软将再次构建一个新的浏览器(除了这一次,基于chromium,这意味着它-理论上-不会完全糟糕)。 :D - dudewad

5

display: flex 在这种情况下可以使用。给父元素添加 display: flex; 然后根据需要给 h1 标签添加边距即可。


1
这是由于外边距折叠所导致的。当子元素触及父元素边界并且它们中的任何一个应用了外边距时,会发生以下情况:
  1. 最大的外边距将获胜(应用)。

  2. 如果它们中的任何一个具有外边距,则两者将共享相同的外边距。

解决方案
  1. 给父元素应用边框,使父元素和子元素分离。
  2. 给父元素应用填充,使父元素和子元素分离。
  3. 在父元素上应用overflow而不是visible。
  4. 使用before或after在父div中创建虚拟元素,可以区分应用于子元素和父元素的外边距。
  5. 在应用外边距的子元素和父元素之间创建一个HTML元素也可以将它们分开。

0
在父元素顶部增加一点点填充即可解决此问题。

.parent{
  padding-top: 0.01em;
}

如果您需要使父元素内的元素在父元素外可见,例如创建重叠效果,则此功能非常有用。


0
今天遇到了这个问题。
当我有更多的元素跟随时,overflow: hidden并没有按预期工作。
所以我尝试改变父级div的display属性,display: flex起作用了!!!
希望这对别人有帮助。 :)

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