兄弟元素垂直外边距合并:正数取大、一正一负取代数和、全负取绝对值大者;父子margin-top塌陷使父容器下移;空元素自身上下margin合并;响应式切换可能突变合并状态;推荐用gap、bfc或微调padding/border规避。

兄弟元素间 margin-bottom 和 margin-top 合并导致间距变小
你写了 margin-bottom: 24px 和 margin-top: 16px,结果两个模块之间只空出 24px,不是预期的 40px——这不是计算错误,是浏览器按规范把它们“压扁”成一个值了。
这种合并只发生在标准文档流中垂直相邻的块级元素之间,比如连续的 <div>、<code><p></p> 或 <section></section>。只要中间没 border、padding、内容或 BFC 隔开,就一定会合并。
- 正数取大:
margin-bottom: 30px+margin-top: 20px→ 实际间距 30px - 一正一负:
margin-bottom: 30px+margin-top: -10px→ 实际间距 20px(代数和) - 全为负:
margin-bottom: -20px+margin-top: -30px→ 实际间距 -30px(绝对值大的那个) - Flex/Grid 子项完全不参与:换成
display: flex或display: grid,gap就能稳稳生效
父子元素间 margin-top 塌陷让整个模块下移
给子模块设了 margin-top: 40px,结果不是它自己往下挪,而是父容器整体被顶下去 40px——这是父子塌陷的典型表现。
触发条件很常见:父容器是普通 <div>,没写 <code>border、没加 padding、里面没文字也没伪元素,也没用 display: flow-root 或 overflow: hidden 触发 BFC。这时候子元素的 margin-top 就会“穿透”父盒,直接跟父容器上边缘合并。
- 调试时看 DevTools 的 Computed 面板:如果父元素的
margin-top显示为 40px,但你在 Styles 里根本没写,基本就是塌陷了 -
overflow: hidden能阻断,但可能裁掉box-shadow、下拉菜单或动画溢出部分 - 更稳妥的是
display: flow-root(Chrome 64+/Firefox 59+/Safari 15.4+ 全支持),语义明确、零副作用 - 轻量替代方案:
padding-top: 1px或border-top: 1px solid transparent
空模块自身上下 margin 合并造成留白不足
一个空的 <div class="divider"></div> 设了 margin: 32px 0,结果上下只撑开 32px,不是 64px——因为空块的 margin-top 和 margin-bottom 自己就合并了。
这类空元素常被用作分隔线、占位符或响应式隐藏后残留节点。只要它满足“无内容、无 padding、无 border、未触发 BFC”,就会自合并。
- 别靠
height: 0挡住合并——高度为 0 不影响塌陷条件 - 想让它真占 64px?加
padding: 1px 0或border: 1px solid transparent - 或者换语义更清晰的方式:
<hr>、伪元素::before/::after,或直接用gap控制容器内间距
响应式切换时 margin 合并状态突变
PC 端看着好好的模块间距,切到手机端突然变大或变小——很可能是因为媒体查询里改了父容器的 display,比如从 flex 切回 block,子项瞬间开始参与 margin 合并。
百分比 margin(如 margin-top: 5%)在合并时参照的父宽可能已随断点变化,结果更难预测。Bootstrap 的 mb-4 在嵌套组件里失效,往往不是类没加载,是外边距被上层容器吞掉了。
- 检查 DOM 结构是否在断点后“变薄”:有没有意外移除 padding/border?有没有 flex 容器降级为 block?
- 避免在响应式逻辑里依赖 margin 合并行为;统一用单边距(如只设
margin-bottom)或改用gap - 空元素在
display: none后又 show 出来,若没重置样式,仍可能保留合并状态
<div>、父容器漏掉的 <code>padding-top: 1px——它们都可能成为 margin 合并的入口。











