如何禁用外边距折叠?

272

有没有办法完全禁用外边距折叠?我找到的唯一解决方案(名为“取消折叠”)涉及使用1像素边框或1像素填充。我觉得这是不可接受的:多余的像素增加了计算的复杂性,却没有好处。有没有更合理的方法来禁用这种外边距折叠?


6
请使用Flex或Grid布局,这两种布局方式不会出现外边距折叠的情况:https://dev59.com/93I-5IYBdhLWcg3wfoW1#46496701 - Michael Benjamin
1
只需为元素的 margin-bottom 赋值,而将 margin-top 保留为 0。 - Dan Bray
我制作了一个包来使计算更加容易:https://www.npmjs.com/package/collapsed-margin - Owen M
1
https://www.joshwcomeau.com/css/rules-of-margin-collapse/ - Bergi
12个回答

342

有两种主要的边距折叠类型:

  • 相邻元素之间的边距折叠
  • 父元素和子元素之间的边距折叠

在后一种情况下,使用填充或边框将防止折叠。此外,将应用于父级的任何overflow值与其默认值(visible)不同,都将防止折叠。因此,overflow: autooverflow: hidden将具有相同的效果。也许仅在使用hidden时唯一的区别是,如果父元素具有固定高度,则会隐藏内容的意外后果。

其他一些属性,一旦应用于父级,可以帮助修复此行为,包括:

  • float: left / right
  • position: absolute
  • display: flex / grid

您可以在此处测试它们:http://jsfiddle.net/XB9wX/1/

我应该补充一点,就像往常一样,Internet Explorer 是个例外。更具体地说,在IE 7中,当为父元素指定某种布局(如width)时,边距不会折叠。

来源:Sitepoint的文章折叠边距


3
注意,如果填充值不为零,它也会影响这个结果。 - Mladen Janjetovic
3
注意,overflow: auto 可能会导致滚动条出现在父元素中,而不是像 overflow: visible 一样让溢出内容溢出。 - Leo
5
感谢display: inline-block,它救了我 :) - alexcasalboni
4
任何与默认值不同的 flex 值都会禁用外边距折叠。 - Oly
12
一旦浏览器的支持程度提高,display: flow-root 可能会成为首选方法。 - James Coyle
显示剩余5条评论

81

有一个很巧妙的技巧可以禁用边距折叠,它对视觉没有影响,据我所知,就是将父元素的内边距设置为0.05px

.parentClass {
    padding: 0.05px;
}

内边距不再是0,因此不会再发生折叠,但同时内边距足够小,可以在视觉上舍入为0。

如果希望应用其他填充,则仅对不需要边距折叠的“方向”应用填充,例如padding-top: 0.05px;

Working example:

.noCollapse {
  padding: 0.05px;
}

.parent {
  background-color: red;
  width: 150px;
}

.children {
  margin-top: 50px;

  background-color: lime;      
  width: 100px;
  height: 100px;
}
<h3>Border collapsing</h3>
<div class="parent">
  <div class="children">
  </div>
</div>

<h3>No border collapsing</h3>
<div class="parent noCollapse">
  <div class="children">
  </div>
</div>

编辑:将值从0.1更改为0.05。正如克里斯·摩根在下面的评论中提到的那样,以及从这个小测试中可以看出,似乎Firefox确实考虑了0.1px的填充。 不过,0.05px似乎可行。


2
这是我最喜欢的解决方案。你甚至可以将其包含为默认样式。为什么不呢?*{padding-top:0.1px}。不过我们确定它在所有浏览器中都能工作吗? - Nick Manning
到目前为止,对我来说运行得相当不错,但我并不声称已经在大多数浏览器中进行了彻底的测试。 - Nicu Surdu
2
非常棒的解决方案,它似乎在大多数浏览器上都可以按预期运行。感谢您的分享! - wiredolphin
4
这是一个靠不住的解决方案,因为在高DPI显示器和子像素计算的情况下,它确实添加了额外的像素。(我相信Firefox早就开始使用子像素布局了,其他浏览器相对较近才跟随。) - Chris Morgan
1
这个解决方案似乎太聪明了,与其他选项相比不太容易理解,因此在生产代码中没有用武之地。 - MTpH9
显示剩余5条评论

69

你也可以使用传统的微清除浮动方法实现这一点。

#container::before, #container::after{
    content: ' ';
    display: table;
}

请查看更新后的代码演示:http://jsfiddle.net/XB9wX/97/


7
我不明白,当我查看那个示例时,边距发生了折叠(div之间的垂直间距仅为10像素,而不是20像素)。 - Andy
1
这只有在消除所有具有此clearfix应用的兄弟姐妹之间的折叠时才有帮助。我已经分叉了示例以证明这一点:http://jsfiddle.net/dpyuyg07/ --- 即使如此,这还不是全部。它仅消除了从您应用该修复程序的元素的子级中产生的边距的折叠。如果您在容器本身上添加边距,则边距仍将折叠,可以在此分支中看到:http://jsfiddle.net/oew7qsjx/ - NicBright
5
我可以更加准确地表达:clearfix 方法只能防止父级和子级之间的外边距折叠,而不能影响相邻兄弟元素间的折叠。 - NicBright
我现在明白Bootstrap倾向于用:before:after元素填充DOM的原因了。我现在已经将这个规则添加到我的样式表中:div:before, div:after{content: ' '; display: table;}。太棒了。突然间,一切都开始按照预期的方式运作了。 - Stijn de Witt
不适用于自闭合元素,例如 <input> - Rockallite
显示剩余2条评论

27

实际上,有一个可以完美运作的方法:

display: flex; flex-direction: column;

只要你能接受仅支持IE10及以上版本

.container {
  display: flex;
  flex-direction: column;
    background: #ddd;
    width: 15em;
}

.square {
    margin: 15px;
    height: 3em;
    background: yellow;
}
<div class="container">
    <div class="square"></div>
    <div class="square"></div>
    <div class="square"></div>
</div>
<div class="container">
    <div class="square"></div>
    <div class="square"></div>
    <div class="square"></div>
</div>


1
为了使其成为通用解决方案,必须在.container中添加一个额外的<div>,否则.container将控制其子元素的框模型。例如,内联元素将变成全宽块级元素;如果它们有边距,那么这些边距也将被折叠。 - zupa

24

overflow:hidden会防止边距折叠,但它并非不带副作用 - 即它会隐藏溢出内容。

除此之外和您提到的问题,您只需学会接受它,并为它有用的那一天做准备(每3至5年出现一次)。


已将我的答案转换为社区维基。我认为我在第二段的最后两行中涵盖了您提到的副作用:_也许使用hidden唯一的区别是如果父元素具有固定高度,则隐藏内容会产生意外后果_。但是,如果您觉得需要进一步澄清,请随时贡献。谢谢。 - HQCasanova
7
дҪҝз”Ёoverflow: autoеҸҜд»ҘйҳІжӯўжәўеҮәйҡҗи—Ҹ并д»Қ然йҳІжӯўиҫ№и·қжҠҳеҸ гҖӮ - Gavin
1
@Gavin,“overflow:auto;”使得我的内容区域在某些页面上出现了滚动条。 - Reed

10
CSS* 修复
display: flow-root;
✅ 父元素折叠
❌ 兄弟元素折叠
display: flex;
flex-direction: column;
✅ 父元素折叠
✅ 兄弟元素折叠

*现代浏览器(不包括IE11)支持display: flow-rootdisplay: flex

示例

section {
  background: green;
  outline: 2px solid purple;
}

p {
  background: yellow;
  margin: 1em 0;
}

section.flow-root {
  display: flow-root;
}

section.flex {
  display: flex;
  flex-direction: column;
}
<h2>Default</h2>  
<section>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</section>

<h2><code>flow-root</code> (Fixes only container)</h2>
<section class="flow-root">
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</section>

<h2><code>flex</code> (Fixes both container & siblings)</h2>
<section class="flex">
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</section>


感谢 AnthumChris 的编辑。这让我想到是否有任何技术可以防止同级元素折叠,同时保留父元素的折叠。这将使我们的答案成为最灵活和完整的解决方案! - Chuanqi Sun

9

我知道这是一个非常老的帖子,但只想说,在父元素上使用flexbox会禁用其子元素的边距折叠。


它不仅适用于其子元素 - 还防止父元素与第一个和最后一个子元素之间的边距折叠。 - Sven Marnach

8
每个基于 Webkit 的浏览器都应该支持属性 -webkit-margin-collapse。还有子属性只针对顶部或底部边距进行设置。您可以将其赋予折叠(默认值)、丢弃(如果存在相邻边距,则将边距设置为 0)和分离(防止边距折叠)的值。
我已经测试了这在 Chrome 和 Safari 的 2014 版本上可以正常工作。不幸的是,我认为这在 IE 中不会得到支持,因为它不是基于 Webkit 的。
详细解释请参考 苹果的 Safari CSS 参考
如果您查看 Mozilla 的 CSS webkit 扩展页面,他们将这些属性列为专有属性,并建议不要使用它们。这是因为它们可能不会很快进入标准 CSS,只有基于 Webkit 的浏览器才会支持它们。

这很好,因为它帮助我们解决了Safari和Chrome处理边距不一致的问题。 - bjudson
2
看起来在Chrome v85中删除了-webkit-margin-collapse属性。我在一些工具中使用它,现在测试失败了。 - Möhre

3
尝试
{
 display:flex;
 flex-direction:column;
}

或者
{
   display:grid;
}

3
为了避免兄弟元素之间的外边距折叠,可以在其中一个兄弟元素上添加display: inline-block;样式(只需要在其中一个上添加即可,虽然也可以同时添加到两个兄弟元素上)。

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