随着各种 UI 库的使用,像这种问题在业务中可能都很少接触,但是仍需了解其现象和解决方案。

一键直达

什么是外边距重叠 —— Margin Collapsing

当块级元素(Block)的上下外边距与其相邻或嵌套的块级元素外边距重叠时,外边距会合并为一个外边距,而不是相加。这种行为成为外边距重叠。(浮动和绝对定位的元素不会发生外边距重叠)

外边距重叠只会发生在块级元素(Block)上,例如 divpsection 等。

外边距重叠计算规则

示例元素

<div class="css-fix-margin-item-parent">
  <div class="css-fix-margin-item-child">child div</div>
</div>
  1. 两个正数的外边距取最大的边距作为外边距
  2. 一个正数一个为负数,外边距为两者之和
.css-fix-margin-item-parent {
  margin-top: 20px;
  background-color: red;

  .css-fix-margin-item-child {
    margin-top: -30px;
    background-color: green;
  }
}

  1. 两个都是负数的外边距,外边距为两者绝对值的最大值
.css-fix-margin-item-parent {
  margin-top: -20px;
  background-color: red;

  .css-fix-margin-item-child {
    margin-top: -30px;
    background-color: green;
  }
}

出现外边距重叠的几个场景

示例可在控制面板调试,释放注释代码即可

相邻兄弟元素的外边距重叠

解决方法:

  • 父级元素设置弹性或网格布局:display: flex | grid or inline-flex 等…
  • 子级底部元素设置:float: left or position: absolute | fixed
  • 统一使用 margin-top or margin-bottom,而非共存
  • 子级相邻之间增加一个占位元素
<style>
  .css-fix-margin-container {
    /*display: flex;*/
    /*flex-direction: column;*/
    /*display: grid;*/

    .css-fix-margin-item-siblings:first-of-type {
      margin-bottom: 20px;
      background-color: red;
    }

    .css-fix-margin-item-siblings:last-of-type {
      margin-top: 30px;
      background-color: green;

      /*position: absolute;*/
      /*float: left;*/
      /*width: 100%;*/
      /*&::after {*/
      /*  content: "";*/
      /*  clear: both;*/
      /*}*/
    }
  }
</style>

<div class="css-fix-margin-container">
  <div class="css-fix-margin-item-siblings">sibling</div>
  <!-- <div>placeholder</div> -->
  <div class="css-fix-margin-item-siblings">sibling</div>
</div>
sibling
sibling

父级与子级的外边距重叠

当父元素无 borderpaddinginline-contentclearance 时,子元素的 margin-top or margin-bottom 会与父元素的 margin 产生重叠问题

解决方法:

  • 父元素添加:外边距方向不为 0 的 paddingborder
  • 父元素创建 BFC 环境,如:display: flex | gridoverflow: hidden 等…
  • 子元素绝对定位:position: absolute | fixed or float: left
  • 父子元素非相邻嵌套(外边距子元素与父元素之间填充内容)
<style>
  .css-fix-margin-container {
    .css-fix-margin-item-parent {
      margin-top: 20px;

      /*border-top: 1px transparent solid;*/
      /*display: inline-block;*/
      /*display: table;*/
      /*padding-top: 1px;*/
      /*position: absolute;*/
      /*overflow: hidden;*/

      .css-fix-margin-item-child {
        margin-top: 30px;
        /*position: absolute | fixed;*/
      }
    }
  }
</style>

<div class="css-fix-margin-container">
  <div class="css-fix-margin-item-parent">
    <!-- <div>placeholder</div> -->
    <div class="css-fix-margin-item-child">child div</div>
  </div>
</div>
child div

空块级元素的外边距重叠

当块级元素没有 paddingborderheightinline content 时,上下外边距会重叠

解决方法:

  • 上面的条件反推即可,自身添加:paddingborderheightinline content
  • 自身创建 BFC 环境,如:display: flex | gridoverflow: hidden 等…
  • 父级元素添加:display: flex | grid
<style>
  .css-fix-margin-container {
    /* display: flex */
    /* display: grid */
    
    .css-fix-margin-item-empty {
      margin-top: 20px;
      margin-bottom: 30px;

      /*border-top: 1px transparent solid;*/
      /*display: inline-block;*/
      /*display: table;*/
      /* any direction & not 0 */
      /*padding-top: 1px;*/
      /*position: absolute;*/
      /*overflow: hidden;*/
    }
  }
</style>

<div class="css-fix-margin-container">
  <div class="css-fix-margin-item-empty"></div>
  <div style="background-color: red">empty</div>
</div>
empty

Mastering margin collapsing
Block formatting context
https://juejin.cn/post/6953500845426081800#heading-2