外边距合并不是bug,而是CSS规范定义的正常行为;发生在常规文档流中垂直相邻且无阻隔的块级元素间,包括相邻兄弟、父子(父无border/padding/BFC)及空块元素自身上下margin,取最大值旨在避免视觉间距累加。

外边距合并不是 bug,是 CSS 规范明确规定的渲染行为——只要满足条件,margin-top 和 margin-bottom 就会折叠成一个值,而不是相加。
哪些元素之间会发生 margin 合并?
只在「常规文档流中的块级元素」之间发生,且必须满足「垂直相邻 + 无阻隔」两个前提。常见组合包括:
- 相邻兄弟元素:比如连续的
<div> 或 <code><p></p> - 父元素与第一个/最后一个子元素:当父元素没有
border、padding、内容或 BFC 触发时 - 空块元素自身上下 margin:比如
<div style="margin: 20px 0"></div>,它的margin-top和margin-bottom会合并
Flex 容器、Grid 容器的直接子元素、浮动元素、绝对定位元素、inline-block 元素,都不会参与 margin 合并。
为什么取最大值,而不是相加?
这是 W3C 的设计选择,目的是避免段落、标题等连续块元素之间产生过大的意外间距。例如:
<p style="margin: 1em">第一段</p> <p style="margin: 1em">第二段</p>
如果按相加算,两段之间就是 2em;但实际只需要 1em 的视觉节奏。规范强制取较大值(此处都是 1em),就保证了语义一致的行距感。
注意:如果有负 margin 参与,规则会变——比如 margin-top: 20px 和 margin-top: -10px 相邻,结果是 10px(20 + (-10));两个负值则取绝对值更大的那个。
为什么加了 padding 或 border 就能阻止?
因为 margin 合并的前提是「相邻且中间无分隔」。只要父元素存在计算后宽度 > 0 的 padding-top、border-top,或者哪怕是一个空格文本节点,就能物理性地打断这种「邻接关系」。
-
padding-top: 1px最轻量,语义也最清晰 -
border-top: 1px solid transparent有效但略冗余 -
overflow: hidden或display: flow-root是通过创建新 BFC 来隔离渲染上下文,本质是让父元素不再和子元素共享同一个外边距计算环境
别用 padding: 0 或 border: none,它们在计算中等于不存在。
最容易被忽略的细节
多个 margin 同时参与折叠时,不能分步计算。比如嵌套三层 div,各自有 margin-top,最终结果是所有相关 margin 值一起参与比较或加减,而不是先算内层再算外层。这个细节在复杂嵌套布局里常导致预期外的间距偏差。











