外边距合并是css规范规定的垂直相邻块级元素margin折叠行为:同号取大、异号相加;仅发生在normal flow中,flex/grid/inline/absolute等布局下不触发。

什么是外边距合并(Margin Collapse)
外边距合并不是 bug,是 CSS 规范明确规定的渲染行为:相邻块级元素的垂直 margin-top 和 margin-bottom 会“折叠”成一个 margin,取两者中较大的那个值(同号时),或相加(异号时)。
典型触发场景包括:父子元素间(父容器无 border/padding、非 flex/grid)、兄弟块元素之间、空块元素自身上下 margin。
它只发生在块流(normal flow)中的垂直方向,display: inline、float、position: absolute、flex、grid 容器内的子项都不会触发。
为什么 margin-top 会“消失”到父容器外面
这是最常被误认为“bug”的现象:子元素设置了 margin-top,但父容器顶部没留空,反而整个父容器被往下推了。
立即学习“前端免费学习笔记(深入)”;
根本原因是父子外边距合并 —— 当父容器没有 border、padding、inline content 或 clear 等“分隔物”,且子元素是第一个块级子元素时,子元素的 margin-top 就会和父容器的 margin-top(通常是 0)合并,最终表现就是“冒出去”了。
- 解决方法之一:给父容器加
padding-top: 1px(最小有效分隔) - 或加
border-top: 1px solid transparent - 或触发 BFC:设
overflow: hidden、display: flow-root(推荐,语义清晰且无副作用) - 避免用
margin-top推子元素,改用padding-top在父容器上预留空间
display: flow-root 是最干净的修复方式
display: flow-root 创建一个无副作用的 BFC,能隔离内外 margin,同时不改变布局流、不截断阴影、不干扰 overflow 行为 —— 比 overflow: hidden 更精准。
兼容性已很好:Chrome 64+、Firefox 59+、Safari 12.1+、Edge 79+。IE 不支持,但 IE 已退出主流维护。
示例:
.container {
display: flow-root; /* 阻断子元素 margin 向上合并 */
}
.container > p {
margin-top: 20px; /* 这个 top margin 现在只作用于 container 内部 */
}注意:display: flow-root 不影响子元素的水平布局,也不强制换行,就只是“让 margin 别乱跑”。
哪些情况 margin 不会合并?一眼判断法
记住三个“只要有一个成立,就不合并”:
- 任意一方是
inline盒子(比如span) - 任意一方是
flex/grid容器的直接子项 - 任意一方设置了
display: contents(此时该元素不生成盒子,自然无 margin 可合并) - 父容器有
border、padding、clear、inline content(哪怕一个空格)
特别注意:浮动(float)和绝对定位(position: absolute)元素完全脱离 normal flow,它们的 margin 不参与任何合并 —— 但这也意味着它们不再影响周围块的布局位置。
真正容易被忽略的是:空块元素(比如 <div></div>)自身的上下 margin 也会合并,结果变成单个 margin,而不是 0。这在用空白 div 做间隔时会导致意料之外的高度。










