Margin会重叠,你造吗

3,857 阅读7分钟

之所以要专门写一篇文章去解释margin重叠,一是因为前面的文章里有提到过,怕有些童鞋不了解;二是要写的内容不是三言两语就能说清楚的。

在讲重叠之前,我们先来了解一下margin这个属性。

一. margin 基础讲解

这个属性呢,太常见,我就大概讲讲,有几点大家注意一下就好。

margin, 实为margin-left, margin-right, margin-top, margin-bottom的一个简写,这些子属性分别用来设置box的左 / 右 / 上 / 下外边距的宽度,它们的具体用法如下:

属性名: margin-left / margin-right / margin-top / margin-bottom
值: <length> | <percentage> | inherit
初始值: 0
继承性: 无
应用对象:所有dom元素,除了display为table-row-group,table-row, table-column-group, table-column, table-header-group, table-footer-group, table-cell
百分比: 参考containing block的宽度
计算值(computed value,参考第4条):开发人员指定的百分比值 或 一个绝对长度

有一些使用细节需要说明一下:

  • margin-top和margin-bottom在inline box(看第18条)上没有任何效果。
  • 属性值设为百分比时,参考对象为containing block的宽度,即使是margin-top,margin-bottom也是酱紫的
  • margin设为一个值时,表明四个子属性均为此值;设为两个值时,表明margin-top和margin-bottom将为第一个值,margin-left和margin-right将为第二个值;设为三个值,表明margin-top取第一个值,margin-left和margin-right取第二个值,margin-bottom取第三个值;设为四个值,则按照top, right, bottom, left的顺序从第一个值开始设置。例如:
margin:20px;  等同于 所有边均为20px

margin:10px 20px; 等同于 margin-top & margin-bottom为10px, margin-left & margin-right为20px

margin:10px 20px 30px; 等同于 margin-top为10px, margin-left & margin-right为20px, margin-bottom为30px

margin:10px 20px 30px 40px; 等同于 margin-top为10px,margin-right为20px,margin-bottom为30px,margin-left为40px

嗯哼~蛮简单的~~那就来点复杂的吧!

二. margin 重叠 详解

何为margin重叠?两个或多个box的相邻margin合在一起,成为一个margin。其实就是两个margin重叠在一块,那么呈现出来的效果当然是一个的咯。

如何才能产生这种效果呢?

首先,你得保证用的是垂直方向的margin(margin-top & margin-bottom)。你要是用margin-left和margin-right,试一百次都不会出现!

其次,应用对象要选好。不是所有box都可以!(突然觉得css里的规则一套一套的,水好深~~)

最后,重叠的环境要准备好。即使对象选好了,重叠也不是百分百就有,只有满足特定的条件才会产生。

重叠对象

在我说出之前,大家可以先想想哪些对象会有margin重叠。

我们可以试试排除法。CSS中的box无非就四种:float box,absolute positioned box,inline-level box, block-level box。

看过前面的定位文章的童鞋应该知道,float box和absolute positioned box都会脱离正常流而自成一条流,流与流之间是各玩各的,互不干扰,那么我们可以先排除这两种。而inline-level box在渲染过程中会参与inline formatting context,这个上下文中的box不会发生margin重叠。那么剩下的只有block-level box。

那么,所有的block-level box都会发生重叠吗?

是的,但是——要排除root box(第28条)

现在,我们大致知道重叠对象会是两个block-level box(不包括root box)。这只是一个初筛条件,这两个重叠对象还必须同属一个block formatting context,具体为什么呢,看看之前介绍bfc的文章就明白了。

重叠环境

对于一个符合条件的box而言,以下任何一种情况都会发生重叠:

  1. top margin 与 它的第一个处于普通流中的孩子的top margin
  2. height 为auto,它的bottom margin 与 它的最后一个处于普通流中的孩子的bottom margin
  3. bottom margin 与 它的下一个处于普通流中的兄弟的top margin
  4. overflow为visible(即该box不会建立bfc), min-height 的computed value(第四条)为0,height的computed value为0或auto,无孩子box,它的top margin与bottom margin

特例:overflow不为visible的block-level box的margin不会与它的任何在普通流中的孩子发生margin 重叠,但可与处在同一bfc的兄弟box发现margin 重叠。

我们来看看示例:

例1:父box与第一个子孩子box

<!DOCTYPE>
<html>
  <head>
      <style>
          .parent{
              margin-top:20px;
              margin-bottom:10px;
              background-color: #e6e96e;
          }
          .child{
              background-color: aquamarine;
          }
          .first{
            margin-top:30px;
            margin-bottom:30px;
          }
      </style>
  </head>
  <body>
    <div class='parent'>
        <div class='child first'>haha</div>       
    </div>
 </body>
</html>

chrome浏览器显示:

很明显,两者margin发生重叠。

例2:box自身的top margin与bottom margin发生重叠 && 兄弟box之间margin重叠 && overflow不为visible的box不与孩子box发生margin重叠

<!DOCTYPE>
<html>
  <head>
      <style>
          .parent{
              width:500px;
              min-height: 0;
              height:auto;
              margin-top:20px;
              margin-bottom:10px;
              background-color: #e6e96e;
          }
          .parent-second{
              overflow:hidden;
          }
          .child{
              background-color: aquamarine;
          }
          .first-child{
            margin-top:30px;
            margin-bottom:30px;
          }
          .second-child{
              width:200px;
              margin-top:60px;
              margin-bottom:60px;
          }
      </style>
  </head>
  <body>
    <div class='parent'>
    </div>
    <div class='parent parent-second'>
            <div class='child first-child'>haha in second div</div>
            <div class='child second-child'>lala in second div</div> 
    </div>
 </body>
</html>

chrom显示如下:

我们看第一个 div.parent ,它的top margin与bottom margin发生重叠,这个重叠结果又与div.parent.second-parent的top margin发生重叠,所以页面最上方的空白处margin只有20px,这个数值可以通过查看div.parent.second-parent的margin得到(下图的橙色部分)。

由上图,我们也可以看到,div.parent.second-parent并未与自己的第一个孩子box发生margin 重叠。

重叠margin计算

假设第一个box的top margin值为A,它的第一个子孩子的top margin值为B,两者margin重叠,重叠结果会按如下规则计算:

A,B均为正值,则取max(A, B)
A为负值,B为正值,则为B-|A|
A,B均为负值,则取0-max(|A|,|B|)

来个例子

为了更好的展示重叠结果,将html元素的top margin设为100px(注:html元素产生的是root box,不会发生margin重叠),同时去掉浏览器为body设置的margin。

<!DOCTYPE>
<html>
  <head>
      <style>
          html{
            margin-top:100px;
          }
          *{
            margin-top:0;
            margin-bottom:0;
          }
          .parent{
              width:100px;
              height:100px;
              background-color: #e6e96e;
          }
          .child{
              width:100%;
              height:100%;
              background-color: aquamarine;
          }
      </style>
  </head>
  <body>
    <div class='parent'>
        <div class='child'>haha</div>       
    </div>
 </body>
</html>

chrome展示如下:

例3:A为负值,B为正值

为div.parent及div.child加上margin-top

          .parent{
              width:100px;
              height:100px;
              margin-top:-60px;
              background-color: #e6e96e;
          }
          .child{
              width:100%;
              height:100%;
              margin-top:10px;
              background-color: aquamarine;
          }

chrome里显示如下:

用inspect方式查看margin的范围:

可以看到,重叠margin值为html元素所设margin值的一半,即50px。它背后的运算过程是:10-|-60| = -50

例4:A, B均为负值

为两个div加上margin-top

          .parent{
              width:100px;
              height:100px;
              margin-top:-10px;
              background-color: #e6e96e;
          }
          .child{
              width:100%;
              height:100%;
              margin-top:-50px;
              background-color: aquamarine;
          }

chrome显示如下:

再查看下margin范围

margin重叠的结果依然为50px,但背后的运算却不同,0 - max(|-10|, |-50|) = 0-50 = -50

小结:只有垂直margin才可重叠,且参与的对象为同一个bfc的block-level box;重叠只有满足特定的条件才会发生;重叠的计算因margin值的正负情况而有所不同。