CSS之margin合并

时间:2024-04-01 19:00:59

合并margin

CSS中,两个或多个盒(可能但不一定是兄弟)的相邻的margin会被结合成一个margin。外边距按这种方式结合叫做合并(collapse),产生的结合的外边距叫做折叠外边距

计算规则

当两个或者更多的margin合并时,产生的margin宽度为合并margin宽度中的最大值。至于负margin,就从正相邻margin的最大值中减去负相邻margin的绝对值的最大值。如果没有正margin,就用0减去相邻margin的绝对值的最大值

合并规则

根据 CSS2.1规范,可以知道以下:

  • 相邻的垂直外边距会合并,除了:

    • 根元素盒的margin不合并
    • 如果一个带有间隙(指clear属性导致元素位置移动形成的间隙)的元素的上外边距与下外边距相邻,它的外边距会和紧挨着的兄弟(元素)的相邻外边距合并,但合并后不会再和父级块的下外边距合并
  • 水平margin不会合并

  • 两个margin是 相邻的 ,当且仅当:

    • 都属于流内(in-flow)块级盒,处于同一个块格式化上下文
    • 没有行框(line box),空隙,内边距和边框把它们隔开(注意,因此某些0高度行框会被忽略)
    • 都属于垂直相邻框边界,即形成下列某一对:
      • 盒的上边距与其第一个流内孩子的上边距
      • 盒的下边距与其下一个流内紧挨着的兄弟的上边距
      • 最后一个流内孩子的下边距与其height计算值为’auto’的父元素的下边距
      • 盒的上边距和下边距,要求该盒没有建立新的块格式化上下文,并且’min-height’计算值为0,‘height’计算值为0或’auto’,还没有流内孩子

margin相邻现象举例说明

1.当两个盒子都属于流内(处于普通文档流内)块级盒,处于同一个块格式化上下文(BFC)。

由此可知,

  • 处于不同BFC的两个盒子的margin不相邻(即可知,可以通过将盒子分别分离到不同BFC中去避免其出现margin重叠现象)
  • 且BFC元素和它的子元素不会发生margin重叠(因为它们处于不同BFC中)
例1,设置div的样式如下,其中margin为20px,可以从图中看出,由于两个div属于流内,且处于同一个BFC中,通过选中可以看出两个div发生margin重叠,两个div之间的间距为20px。
div {
	width: 100px;
	height: 100px;
	background: red;
	margin: 20px;
}
	<div></div>
	<div></div>

CSS之margin合并

当元素脱离文档流时,不会发生margin重叠,如下:

div {
	width: 100px;
	height: 100px;
	background: red;
	margin: 20px;
	float: left;
}
	<div></div>
	<div></div>
	<div></div>
	<div></div>

CSS之margin合并

当元素处于不同BFC时,不会发生margin重叠,如下:

.content {
	width: 100px;
	height: 100px;
	background: red;
	margin: 20px;
}

.bfc {
	overflow: hidden;
}
<div class="bfc">
	<div class="content"></div>
</div>
<!--两个content处于不同BFC中-->
<div class="content"></div>

CSS之margin合并

例2.当父、子元素都是流内元素,且属于同意BFC时,出现margin重叠(father到根元素的margin最终为son的30px)
.father {
	width: 100px;
	height: 100px;
	background: red;
	margin: 20px;
}
.son {
	width: 50px;
	height: 50px;
	background: yellow;
	margin: 30px;
}
<div class="father">
	<div class="son"></div>
</div>

CSS之margin合并

当设置父元素father设置为脱离文档流时,可以看出,father和son没有出现margin重叠现象

.father {
	width: 100px;
	height: 100px;
	background: red;
	margin: 20px;
	float: left;
}

由于设置float和定位就等于将father变成了BFC,即就让father和son处于了不同BFC中,结果和上述一样,这里就不在赘述了。

2.没有行框(line box),空隙,内边距和边框把它们隔开

意思就是说,两个margin之间接触,中间没有其他东西,就会出现重叠。

例3,父元素设置border,就可以看到父子元素之间没有出现margin重叠

CSS之margin合并

例4,当一个元素设置了margin,但是该元素高度为0时,也会出现margin重叠,如下
.targ {
	width: 100px;
	height: 0;
	margin: 20px;
}
.sbling{
	width: 50px;
	height: 50px;
	background: yellow;
}
<div class="targ"></div>
<div class="sbling"></div>

CSS之margin合并
当设置了padding时,就不会了,如下:
CSS之margin合并

3. 最后一个流内孩子的下边距与其height计算值为’auto’的父元素的下边距,即当父元素的高度为auto时,其marginbottom和其最后一个流内子元素的marginbottom会合并。

例5,father的高度为auto,它和它的最后一个流内孩子son的下边距重叠,最后father和sibling之间的间距为150px,如下
	.father {
        width: 100px;
        margin-bottom: 100px;
    }
    .son {
        width: 100px;
        height: 100px;
        margin-bottom: 150px;
        background: red;
    }
    .sibling {
        width: 100px;
        height: 100px;
        background: yellow;
    }
	<div class="father">
		<div class="son"></div>
	</div>
	<div class="sibling"></div>

CSS之margin合并
当给father设置height之后发现,此时sibling与father的垂直距离,只跟它们的margin值有关,与child的margin值无关,如下:
CSS之margin合并
当给father设置padding、border之后,可以发现father的高度被自动撑开为250px,此时它与sibling之间的距离也只受他们之间margin值的影响,如下:
CSS之margin合并

4.盒的上边距和下边距,要求该盒没有建立新的块格式化上下文,并且’min-height’计算值为0,‘height’计算值为0或’auto’,还没有流内孩子

例6,content没有建立新的BFC,且高度为0,并且没有流内孩子,其与sibling的间距为100px,即其上下边距发生了合并
	.content {
        width: 100px;
        height: 0px;
        margin: 100px;
    }
    .sibling {
        width: 100px;
        height: 100px;
        background: yellow;
    }
	<div class="content">
	</div>
	<div class="sibling"></div>

CSS之margin合并
当设置content为BFC后(设置padding、border、height同样),间距为200px,如下,
CSS之margin合并

总结

只要两个margin之间被“隔开”了,包括被分离到不同BFC和被border、padding、高度、空隙或者其他内容隔开,就不会发生margin合并

以下摘自 CSS2.1规范

  • 浮动的盒与任何其它盒之间的margin不会合并(甚至一个浮动盒与它的流内子级之间也不会)
  • 建立了新的块格式化上下文的元素(例如,浮动盒与’overflow’不为’visible’的元素)的margin不会与它们的流内孩子合并
  • 绝对定位的盒的margin不会合并(甚至与它们的流内子级也不会)
  • inline-block盒的margin不会合并(甚至与它们的流内子级也不会)
  • 流内块级元素的bottom margin总会与它的下一个流内块级兄弟的top margin合并,除非该兄弟(元素)具有间隙
  • 流内块级元素的top margin会与它的第一个流内块级子级的top margin合并,条件是该元素没有上边框和上内边距,并且其孩子不具有间隙
  • 一个’height’为’auto’并且’min-height’为0的流内块级盒的bottom margin会与它的最后- - 一个流内块级子级的bottom margin合并,条件是该盒没有下内边距和下边框,并且其孩子的下外边距没有与具有间隙的上外边距合并
  • 盒自身的外边距也会合并,条件是’min-height’属性为0,既没有上下边框,也没有上下内边距,‘height’为0或’auto’,且不含行框的话,那么其所有流内孩子的外边距(如果存在的话)都会合并