这是CSS规范定义的外边距折叠行为,发生在块级元素普通流中垂直相邻且无分隔的margin间,取最大值仅适用于全为正数情形,含负值时按规则相减或取绝对值最大者。

垂直 margin 折叠只发生在块级元素的普通文档流中
这不是浏览器 bug,而是 CSS 规范明确规定的布局行为。只要满足三个条件:元素是块级、处于 normal flow(非浮动/非绝对定位/非 flex/grid 直接子项)、垂直方向上的 margin 相邻且中间无 border/padding/content 隔断,折叠就会发生。
常见误判点:display: inline-block 或 float: left 的元素,其 margin 不参与折叠;flex 容器里的直接子元素,哪怕写了 margin-top 和 margin-bottom,也不会和兄弟元素折叠——因为它们已脱离块级格式化上下文(BFC)的默认规则。
- 父元素没设
padding-top,第一个子元素的margin-top会“冒出去”,表现为父元素整体下移 - 两个
<p></p>标签默认带margin,相邻时顶部和底部 margin 实际只生效一个 - 空
<div> 同时设 <code>margin-top: 20px和margin-bottom: 30px,最终高度仍是 0,不是 50px折叠计算不是简单取 max,负 margin 会让结果变小甚至反向
很多人以为
margin-bottom: 20px和margin-top: 30px折叠后就是30px,这仅在两者都为正时成立。一旦出现负值,计算逻辑立刻变化:- 全为正:取最大值(
20px和30px→30px) - 一正一负:正值减去负值绝对值(
20px和-15px→5px) - 全为负:取绝对值最大者,再加负号(
-10px和-25px→-25px) - 多个 margin 相邻(比如嵌套三层,每层都有
margin),必须所有值一起参与计算,不能分步叠加
例如:
margin-top: 50px、margin-top: -60px、margin-bottom: 150px三者相邻,最终折叠结果是150px + (-60px) = 90px,不是先算前两个得-10px再和150px算。立即学习“前端免费学习笔记(深入)”;
阻止折叠的关键是打破“相邻”或“同属一个 BFC”
真正起作用的不是“加个 padding”,而是它让父元素和子元素的 margin 不再“相邻”——中间多了 1px 的实体分隔。同理,
overflow: hidden是靠触发 BFC,让父元素成为独立格式化上下文,子元素的 margin 就不再和它“同处一室”了。-
display: flow-root是现代首选,语义清晰、无裁剪副作用,兼容性已覆盖 Chrome 65+/Firefox 59+/Safari 15.4+ -
border-top: 1px solid transparent或padding-top: 1px最简单,但可能干扰设计稿像素级对齐 -
gap在flex或grid布局中彻底绕过 margin,但需重构容器 display 类型 - 统一约定只用
margin-bottom,配合:last-child { margin-bottom: 0 },适合列表、文章段落等线性结构
最容易被忽略的折叠场景:空元素自身 margin 折叠
一个空
<div>,既没内容、也没 <code>height、padding、border,此时它的margin-top和margin-bottom会彼此折叠——最终对外表现为单个 margin,而不是两者之和。这种现象常出现在用 div 占位、或 JS 动态插入内容前的“骨架”结构里。你设了
margin: 40px 0,却发现元素上下只撑开 40px 高度,不是 80px,就是因为自身上下 margin 折叠了。修复方式很简单:加
min-height: 0或padding: 1px,哪怕只是 1px,也足以打断折叠条件。 - 全为正:取最大值(


















