前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库垂直外边距合并 相邻兄弟 margin collapsing
CSS盒模型与排版

上下两个 div 各设 20px 外边距,为什么间距只有 20px?

常规流里,上一个块的 margin-bottom 和下一个块的 margin-top 挨在一起时,会合并成一个外边距,取两者中较大的值。所以两边各 20px,中间只有 20px,不是 40px。

前端进阶之旅 · 一题精讲更新于 2026.09.29
CSS#盒模型与排版
先看核心答案读代码示例
理解线索

合并的三个条件

  1. 常规流里的块浮动、绝对定位、inline-block、Flex 和 Grid 子项都不参与
  2. 垂直方向只有上下外边距合并,左右外边距各算各的
  3. 中间没有隔开两个外边距之间没有边框、内边距、内容或清除浮动

给其中一个元素设 display: flow-root 建立 BFC,挡不住它和兄弟之间的合并。BFC 只隔开自己和子元素的外边距。

核心回答

先记住这个答案

外边距合并是常规流里块级元素的规则:上一个块的 margin-bottom 和下一个块的 margin-top 挨在一起时,不会相加,而是合并成一个。两个都是正数就取较大的,所以各 20px 最后只有 20px。这样设计是为了排版:段落都写 margin: 1em 0,段与段之间就是 1em,不会变成 2em。想避免合并,最简单的是让父容器变成 Flex 或 Grid,或者团队约定只用单方向的外边距。

  • 相邻块的上下外边距合并,都为正时取较大值
  • 一正一负时相加,都为负时取绝对值最大的
  • 左右外边距永远不合并
  • Flex、Grid 子项之间不会合并

正负外边距怎么算

合并后的值不是简单地取最大,要看正负。

三种组合HTML
<style>
  .a { margin-bottom: 30px; }
  .b { margin-top: 20px; }  /* 都为正:取大的,间距 30px */

  .c { margin-bottom: 30px; }
  .d { margin-top: -10px; } /* 一正一负:相加,间距 20px */

  .e { margin-bottom: -30px; }
  .f { margin-top: -10px; } /* 都为负:取绝对值大的,间距 -30px,两块重叠 */
</style>

规则可以记成一句:最大的正值加上最小的负值。只有正数时负值部分是 0,只有负数时正值部分是 0。三个以上的外边距连在一起合并时也是这么算,比如父元素的 margin-top、它第一个子元素的 margin-top、上一个兄弟的 margin-bottom 可能一起合并。

什么情况下不会合并

合并只发生在常规流的块级盒子之间,而且两个外边距要真的挨着。下面这些情况都不会合并。

父容器是 Flex 或 Grid 时,子元素之间的外边距各算各的,20px 加 20px 就是 40px。现在用 gap 控制间距的布局越来越多,基本不会碰到合并问题。

元素是浮动、绝对定位或 inline-block 时,它脱离了常规流里块与块的排列,外边距不和别人合并。

左右外边距在任何情况下都不合并。所以这个问题只和垂直方向有关,严格说是和块轴方向有关,竖排文字时合并的是左右外边距。

BFC 为什么挡不住兄弟合并
很多资料说「触发 BFC 就能阻止外边距合并」,这句话只对了一半。BFC 是一个独立的布局区域,它隔开的是自己和子元素之间的外边距,典型场景是父元素的 margin-top 和第一个子元素的 margin-top 合并。但 BFC 元素本身仍然在外层的常规流里,它的外边距照样和兄弟合并。想隔开两个兄弟,要把其中一个包进一个新的 BFC 容器里,或者直接用 Flex 布局。

利用和规避的实际做法

利用合并的典型例子是文章排版。标题、段落、列表各自写上下外边距,不管谁挨着谁,间距都是两者中较大的那个,不会出现标题下面空一大块的情况。

规避合并最省心的做法,是团队约定只用 margin-bottom,不写 margin-top。外边距只朝一个方向,就不存在两个挨在一起的情况。组件库做列表、表单项时也常用这个约定,或者直接交给父容器的 gap。

回答前,多想一步

容易答错的地方

以为合并是取两个值的和
合并的意思是只留一个,不是叠加。都为正时结果是较大值,只有一正一负时才是相加。
以为设了 display: flow-root 兄弟就不合并
flow-root 让元素自己成为 BFC,隔开的是它和子元素,不是它和兄弟。兄弟之间照样合并。
以为空元素不影响间距
一个没有内容、边框、内边距和高度的空块,它自己的上下外边距会先合并,再和前后兄弟的外边距一起合并。页面里留着一个空 div 带着外边距,间距就可能莫名变大。
试着用自己的话回答

面试官还会怎么问?

父子之间的外边距合并怎么解决?

子元素的 margin-top 会穿出父元素,和父元素的外边距合并,表现为父元素整体往下移。给父元素加 padding-top 或 border-top 隔开,或者设 display: flow-root 建立 BFC 都能解决。

为什么 Flex 布局里不会合并?

Flex 项目按 Flex 布局算法排列,不是常规流里的块级盒子。规范只给常规流的块定义了外边距合并,Flex 和 Grid 都没有这条规则。

margin-top 和 margin-bottom 选哪个统一?

一般统一用 margin-bottom,因为文档是从上往下流的,每个元素负责和下一个元素拉开距离,最后一个元素用 :last-child 去掉即可。用 margin-top 也行,关键是全项目统一一个方向。

从一道题,走向一组知识

把知识连起来

盒模型与排版

display: none 和 visibility: hidden 都能隐藏元素,区别到底在哪?

display: none 的元素不占位,它两边的兄弟会变成相邻,外边距跟着合并。

盒模型与排版

div 写 width: 100% 为什么会撑破父容器,width: auto 却不会?

同样是常规流里块级盒子的尺寸规则,一个管水平方向的宽度,一个管垂直方向的间距。

参考资料

  • Mastering margin collapsing - MDN

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 正负外边距怎么算
  3. 什么情况下不会合并
  4. 利用和规避的实际做法
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑