一、margin移动的参考基线

图片描述

上图解析:

图片描述

box 的实际大小 = box 的物理大小 + 正的 margin(物理大小指的是除去 margin,也就是包含 border 以内的 box 大小)

如果是负的 top 或 left 值会引起 box 的向上或向左位置移动,如果是负的 bottom 或 right 会影响下面 box 的显示的参考线。

二、负margin-bottom

一个没有设定高度的块状元素,其高度是自动的,具体来说就是由它里面的文档流最后的位置决定的。

margin-bottom为负值,会导致元素的边界收缩,其作用只会影响文档流的边界。而文档流边界的减少,会产生以下两个影响。
1、后面的元素会占据收缩产生的那一部分文档流,从而形成后面元素覆盖前面元素的效果
2、当父元素没有明确指定height,会导致父元素的边界会往上面缩,也就是其父元素的边界在子元素边界上面。

总之:margin-bottom为负值只会影响父元素的高度(前提是父元素没有明确指定height),无法影响子元素自身的高度!

三、负margin-right

margin-right为负数只会改变元素自身的宽度(前提是父元素尺寸固定,子元素宽度未设),不会修改父元素的宽度。margin-left为负数在该条件下也会改变元素自身的宽度。

为什么负margin-right/margin-left会改变元素宽度?因为假如P为block元素且没有指定width,则p的width+padding+border+margin=父级div的width(这里都是说的水平方向)。

这里假定padding,border为0。父级div width为400px。p的width为inherit。不设置margin,则p的width为400px。
当margin-left:-100px;,p.width + (-100px) = 400px。因此, p的width就变成了500px。

这里说的p都是假定为inherit width。如果指定了p的width,则margin-left,margin-top为负值会引起p元素位置的变化。

四、负margin的应用

多列等高布局(原理:负margin-bottom)

body,
p {
    margin: 0;
    padding: 0;
}

#testdiv {
    overflow: hidden;
    width: 660px;
    margin: 0 auto;
}

#left,
#center,
#right {
    margin-bottom: -400px;
    padding-bottom: 400px;
}

#left {
    float: left;
    width: 180px;
    background: #777;
}

#center {
    float: left;
    width: 300px;
    background: #888;
}

#right {
    float: right;
    width: 180px;
    background: #999;
}

p {
    color: #FFF;
    text-align: center
}

<div id="testdiv">
    <div id="left">
        <p style="height:50px">style="height:50px"</p>
    </div>
    <div id="center">
        <p style="height:100px">style="height:100px"</p>
    </div>
    <div id="right">
        <p style="height:200px">style="height:200px"</p>
    </div>
    <div style="clear:both;"></div>
</div>

未设置padding-bottom和 margin-bottom属性时,高度不一,外层DIV高度为内层最高DIV高度。
图片描述

设置padding-bottom和 margin-bottom属性,未设置testdiv的overflow属性时,外层DIV高度仍为200,内层各div边界在外层div边界之下。
图片描述

图片描述

设置testdiv的overflow属性后,外层div以内层最高div的高度200为自身的高度,各列不足200高度的,则用padding不足。
图片描述

去除列表右边距(原理:负margin-right/margin-left)

可实现中间带些间隔的布局。

ul,
li {
    list-style: none;
    padding: 0;
    margin: 0;
}

.container {
    height: 210px;
    width: 490px;
    border: 5px solid #000;
    overflow: hidden;/*将超出部分内容隐藏*/
}

ul {
    height: 210px;
    background-color: red;
    margin-right: -30px;
    /*一个负的margin-right,相当于把ul的宽度向右增加了30px*/
}
   
li {
    height: 100px;
    width: 100px;
    background: #eee;
    float: left;
    margin-right: 30px;
}
<div class="container">
    <ul>
        <li>子元素1</li>
        <li>子元素2</li>
        <li>子元素3</li>
        <li>子元素4</li>
    </ul>
</div>

ul不加 margin-right: -30px;,则一行放不下

clipboard.png

ul加上 margin-right: -30px;,则会导致超出父元素

图片描述

因此需要为父元素添加overflow: hidden;

图片描述

五、margin折叠

折叠含义

两个或多个毗邻的普通流中的块元素垂直方向上的 margin 会折叠

1、两个或多个

说明其数量必须是大于一个,又说明,折叠是元素与元素间相互的行为,不存在 A 和 B 折叠,B 没有和 A 折叠的现象。

2、毗邻

是指没有被非空内容、padding、border 或 clear 分隔开,说明其位置关系。

注意一点,在没有被分隔开的情况下,父元素的 margin-top 会和它普通流中的第一个子元素(非浮动元素等)的 margin-top 相邻; 只有父元素的 height 是 "auto" 的情况下,它的 margin-bottom 才会和它普通流中的最后一个子元素(非浮动元素等)的 margin-bottom 相邻。

3.垂直方向

是指具体的方位,只有垂直方向的 margin 才会折叠,也就是说,水平方向的 margin 不会发生折叠的现象。

发生折叠的情况

1、相邻的兄弟元素

上一个元素的margin-bottom与下一个元素的margin-top重叠。

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

父元素的margin-top与子元素的margin-top,或父元素的margin-bottom与子元素的margin-bottom重叠。

3、空的block元素

自己的margin-top和margin-bottom重叠(自身内容为空,垂直方向上 border、padding 为 0发生)

如何使元素上下margin不折叠

1、使元素脱离普通流

浮动元素、inline-block 元素、absolute和fixed定位元素的 margin 不会和垂直方向上其他元素的 margin 折叠。(这里指的是上下相邻的元素)

创建了块级格式化上下文的元素,不和它的子元素发生 margin 折叠。可通过以下几种触发BFC:float(除了none)、overflow(除了visible)、display(table-cell/table-caption/inline-block)、position(除了static/relative)

2、使元素不毗邻

添加border或padding或line boxs

margin重叠的计算规则

1、正正取大值(都为正,则取最大的正值)
2、正负值相加(一正一负,则取两者相加后的值)
3、负负最负值(都为负,则取绝对值大的负值)
参考自:
由浅入深漫谈margin属性
深入理解margin重叠以及负margin对元素大小的影响
collapsing-margin的W3C官方介绍


lijinxieyang
356 声望13 粉丝