CSS-深入理解之margin重叠

2,944 阅读4分钟

margin重叠的特性

  • 只发生在block水平的元素(不包含float和absolute的元素)
  • 不考虑writing-mode,只发生在垂直方向(margin-top,margin-bottom)

margin重叠发生的三种情景

  • 相邻的兄弟元素之间发生margin重叠
  • 父级和第一个或最后一个子元素之间发生margin重叠
  • 空的block元素,自己同自己发生margin重叠

1. 相邻的兄弟元素

p{
    line-height: 2em;
    margin: 1em 0;
    background-color: #999;
}
<p>第一行</p>
<p>第一行</p>

理想情况下两个p标签之间距离应该有2em,(第一行的margin-bottom + 第二行的margin-top),而此处两个p标签之间距离只有1em,发生margin重叠

2. 父级和第一个/最后一个子元素

.father{
    background-color: #aaa;
}
.son{
    margin-top:80px;
}

<div class="father">
    <div class="son">I'm son.</div>
</div>

理想情况下margin-top区域的颜色应该为father的背景色,而此处颜色并非#aaa 发生margin重叠

再来看更有意思的

<div class="father" style="margin-top: 80px">
    <div class="son" style="margin-top: 80px">I'm son.</div>
</div>

<div class="father" style="margin-top: 80px">
    <div class="son">I'm son.</div>
</div>

以上三段代码效果居然完全一致,除了第三个效果如我们所想,另外两个都发生了margin重叠

消除父子margin重叠

margin-top重叠

  1. 父元素为块状格式化上下文元素BFC
    <div class="father" style="overflow: hidden;">
        <div class="son" style="margin-top: 80px">I'm son.</div>
    </div>
    
  2. 父元素有border-top设置
    <div class="father" style="border-top: 2px solid #000">
        <div class="son" style="margin-top: 80px">I'm son.</div>
    </div>
    
  3. 父元素有padding-top设置
    <div class="father" style="padding-top: 20px">
        <div class="son" style="margin-top: 80px">I'm son.</div>
    </div>
    
  4. 父元素和第一个子元素之间有inline元素隔开
    <div class="father">
        &nbsp;
        <div class="son" style="margin-top: 80px">I'm son.</div>
    </div>
    

margin-bottom重叠

  1. 父元素为块状格式化上下文元素BFC
  2. 父元素有border-bottom设置
  3. 父元素有padding-bottom设置
  4. 父元素和最后一个子元素之间有inline元素隔开

以上四种处理方式同margin-top的处理方式一致

  1. 父元素有height,min-height,max-height设置

    <div class="father">
        <div class="son" style="margin-bottom: 80px">I'm son.</div>
    </div>
    

    加上height相关设置

    <div class="father" style="height: 60px">
        <div class="son" style="margin-bottom: 80px">I'm son.</div>
    </div>
    

    若设置margin-bottom后超出father的高度范围则无效,不会影响后面的盒子布局

    <div class="father"style="height: 60px">
        <div class="son" style="margin-bottom: 80px">I'm son.</div>
    </div>
    <div style="height: 20px; background-color:#000"></div>
    

3. 空的block元素

<div class="father" style="background-color: #aaa; overflow: hidden;">
    <div class="son" style="margin: 80px 0; "></div>
</div>

理想情况下father的高度应为80+80=160,而此处只有80px,发生margin重叠

消除空block元素margin重叠

  1. 元素有border设置

    <div class="father" style="background-color: #aaa; overflow: hidden;">
        <div class="son" style="margin: 80px 0; border:1px solid #000"></div>
    </div>
    

  2. 元素有padding设置

    <div class="father" style="background-color: #aaa; overflow: hidden;">
        <div class="son" style="margin: 80px 0; padding:20px"></div>
    </div>
    

  3. 元素里有inline元素

    <div class="father" style="background-color: #aaa; overflow: hidden;">
        <div class="son" style="margin: 80px 0;">&nbsp;</div>
    </div>
    

  4. 有height或min-height设置

    <div class="father" style="background-color: #aaa; overflow: hidden;">
        <div class="son" style="margin: 80px 0; min-height: 20px"></div>
    </div>
    

margin重叠的意义

  • 连续段落或者列表之类,如果没有margin重叠的话,首尾项间距会和其他兄弟标签1:2关系,排版不自然。
  • web中任何地方嵌套或者直接放入裸div,不会影响原来的布局。
  • 遗落的任意多个空p标签,不要影响原来的阅读排版。

善用margin

做列表的时候,虽然只设置margin-top也可以达到布局的目的

.list { 
    margin-top: 20px;
}

但是为了健壮性,可以设置margin-top和margin-bottom,虽然会发生margin重叠,但当假如最后一个元素被移除或者位置被置换了,都不会破坏原来的布局样式。

.list { 
    margin-top: 20px;
    margin-bottom:20px;
}

参考

正确看待css的margin重叠