margin 塌陷

解释相邻块级元素为什么会发生 margin 塌陷,以及常见的规避思路。

#type / concept #status / growing #resource / css #tech / dev / frontend

[!info] related notes

margin 塌陷

一句话定义

垂直方向上相邻块级元素的外边距不会简单相加,而是按照特定规则合并为一个值,这就是 margin 塌陷(margin collapse)。

核心机制 / 工作原理

CSS 规范规定:在普通块级格式化上下文(BFC)中,垂直方向相邻的块级元素的 margin 会合并(collapse),取较大值而非两者之和。这是 CSS 的设计行为,不是 bug。

触发条件

margin 塌陷只发生在垂直方向(block flow direction),水平方向的 margin 永远不会塌陷。

三种塌陷场景详解

场景一:相邻兄弟元素

.box1 { margin-bottom: 20px; }
.box2 { margin-top: 30px; }

直觉:间距 = 20 + 30 = 50px。实际:30px(取较大值)。

<div class="box1">上</div>
<div class="box2">下</div>
<!-- 两者间距为 30px,不是 50px -->

场景二:父子元素

.parent { margin-top: 0; }  /* 无 border/padding */
.child { margin-top: 30px; }

子元素的 margin-top 会”穿透”父元素,变成父元素的 margin-top

<div class="parent">
  <div class="child">内容</div>
</div>
<!-- parent 顶部出现 30px 间距,child 仍在 parent 内顶部 -->

场景三:空块级元素

.empty { margin-top: 20px; margin-bottom: 30px; }

一个没有内容、padding、border 的空块元素,自身的 margin-topmargin-bottom 会合并为 30px。

解决方案

1. 创建 BFC(块级格式化上下文)

BFC 内部的元素不会与外部发生 margin 塌陷:

.parent {
  display: flow-root;  /* 最简洁的创建 BFC 方式 */
}

其他创建 BFC 的方式:overflow: hiddenoverflow: autodisplay: flexdisplay: grid 等。

2. 使用 padding 或 border 替代

.parent {
  padding-top: 1px;  /* 任意非零值 */
}
/* 或 */
.parent {
  border-top: 1px solid transparent;
}

paddingborder 会阻断 margin 塌陷。

3. 改用 Flex 或 Grid 布局

.container {
  display: flex;
  flex-direction: column;
  gap: 20px;  /* 用 gap 控制间距,不存在塌陷问题 */
}

Flex/Grid 容器中的子元素不参与 margin 塌陷。

最小例子

<div style="margin-bottom: 20px; background: lightblue;">A</div>
<div style="margin-top: 30px; background: lightcoral;">B</div>
<!-- A 和 B 之间间距 30px,不是 50px -->
<!-- 修复版本 -->
<div style="display: flow-root;">
  <div style="margin-bottom: 20px; background: lightblue;">A</div>
  <div style="margin-top: 30px; background: lightcoral;">B</div>
</div>
<!-- 现在间距是 50px -->

边界与常见误解

  • 误解:margin 塌陷是浏览器 bug。 它是 CSS 规范的正式行为,所有浏览器一致实现。
  • 误解:水平方向也会塌陷。 只有垂直方向(block flow direction)才会。
  • 误解:Flex/Grid 容器中也会塌陷。 Flex/Grid 容器中的子元素不参与 margin 塌陷。
  • 边界:负 margin 也参与塌陷。 合并规则:正正取大、负负取小(绝对值大)、正负则相加。
  • 边界:overflow: hidden 创建 BFC 有副作用,可能裁剪内容。推荐使用 display: flow-root

最短记忆方式

垂直相邻块元素的 margin 不一定相加;遇到奇怪间距,先怀疑是不是塌陷了。用 display: flow-root 或 Flex/Grid 布局可解决。

创建于 2026/3/25 更新于 2026/5/27