margin 折叠是指垂直相邻块级元素的 margin-top 与 margin-bottom 合并为较大值的现象,仅发生于普通文档流中;加 border 或 padding 可插入屏障阻止折叠;推荐用统一 margin 方向、BFC 或 gap 替代。

什么是 margin 折叠(collapsing margins)
当两个垂直相邻的块级元素的 margin-top 和 margin-bottom 直接接触时,浏览器会把它们合并成一个 margin,取其中较大的那个值——这就是 margin 折叠。它只发生在普通文档流中的块级盒子之间,常见于 <div>、<code><p></p>、<h1></h1> 等元素。
典型表现:你给一个 <p></p> 设了 margin-bottom: 20px,下一个 <p></p> 设了 margin-top: 30px,结果两者间距不是 50px,而是 30px。
加 border 或 padding 为什么能阻止折叠
margin 折叠发生的前提是“相邻且无隔离”。只要在两个可能折叠的 margin 之间插入一个“屏障”,折叠就失效。这个屏障可以是:
- 非零的
border(哪怕只有1px solid transparent) - 非零的
padding(哪怕只有padding-top: 1px) - 创建 BFC 的容器(如
overflow: hidden)
关键点:这个屏障必须属于其中一个参与折叠的元素自身,或其父容器(且该父容器需满足 BFC 条件)。单纯给父元素加 padding 不一定管用,要看结构。
立即学习“前端免费学习笔记(深入)”;
实际中更稳妥的写法有哪些
光靠 border 或 padding 容易引入视觉干扰或破坏布局预期,推荐组合策略:
- 对列表项或段落流,统一用
margin-bottom,避免同时设margin-top和margin-bottom - 父容器启用 BFC:
overflow: hidden、display: flow-root(现代推荐)、contain: layout - 用
gap替代 margin(仅限 Flex/Grid 容器内子项) - 若必须用 border 隔离,优先选
border-top: 1px solid transparent,比padding更轻量且不影响盒尺寸计算(除非 box-sizing 是 content-box)
示例:两个 <div> 垂直紧贴,想保持各自 margin 不折叠:<pre class='brush:php;toolbar:false;'>.item {
margin: 20px 0;
}
.item + .item {
border-top: 1px solid transparent; /* 插入屏障 */
}</pre><h3>容易被忽略的边界情况</h3>
<p>margin 折叠不只发生在兄弟元素间,还可能跨层级:</p>
<ul>
<li>父元素和第一个/最后一个子元素的 margin 也可能折叠(尤其父元素没 border/padding/BFC)</li>
<li>空块级元素(如 <code><div></div>)会完全消失,其 margin 仍参与折叠
gap 控制,不是靠 margin)最常踩的坑是:以为加了 padding 就万事大吉,结果发现父容器没设 box-sizing: border-box,导致整体高度意外增加;或者用了 display: inline-block 却忘了换行符产生的空白间隙。


















