
本文共 3427 字,大约阅读时间需要 11 分钟。
在项目中遇到一个问题,有一个父元素中嵌套了一个子元素,代码如下:
效果如下:

margin-top: 20px;
,然后就发现问题:给子元素加了margin-top后,父元素也被顶下来了。 .parent { .children { margin-top: 20px; }}
效果如下:

后来通过给子元素设置padding-top: 20px;
解决问题。
其实一般的做法是给父元素内设置padding,这样就不会出现外边距合并的问题
项目中尽量给父元素设置padding,而不是子元素用margin、padding向外顶,就可以避免很多溢出、塌陷的问题
后来查了一下,这个实际上就是 BFC 中的外边距合并。
什么是外边距合并
外边距合并指的是,当同一个 BFC 中的两个垂直外边距相遇时,它们将形成一个外边距。合并后的外边距的高度等于两个发生合并的外边距的高度中的较大者。而左右外边距不合并。
在CSS当中,相邻的两个盒子(内部嵌套顶部或者底部相邻,也可以是上下相邻)的外边距可以结合成一个单独的外边距。这种合并外边距的方式被称为折叠,并且因而所结合成的外边距称为折叠外边距。
注意:只有普通文档流中块框的垂直外边距才会发生外边距合并。行内框、浮动框或绝对定位之间的外边距不会合并。
边距合并的三种情况
1. 内外div之间上下外边距合并(子元素越界或者说margin越界)
如果块级父元素不存在上边框(border-top)、上内边距(padding-top)、内联元素、清除浮动这四个属性,那么这个元素和第一个子元素的上边距就会重合,这个时候两个盒子的上边距就会合并。父元素对外展现出来的边距为父元素和这个子元素的margin-top的较大者。
margin-top: 20px;
的外边距,会导致父元素也具有了20px的外边距,父元素也会被往下顶。 
.parent { width: 200px; min-height: 100px; background-color: red;}.child { width: 100px; height: 50px; margin-top: 20px; /* 给子元素加一个外边距 */ background-color: yellow;}
类似的,如果块级父元素的margin-bottom与最后一个子元素的margin-bottom之间没有父元素的border、padding、inline-content、height、min-height、max-height分隔时,也会发生下边距合并现象。
顺便说一下,父元素没有height属性或设置min-height、max-height属性时,父元素高度会随子元素高度而改变。当父元素设置了height之后,父元素的高度则不受子元素高度影响。
1)如下图所示,父元素不加height或者设置min-height、max-height时,子元素高度加到200px,父元素也被撑大,适用于盒子高度随内容增加的场景。

.parent { width: 200px; min-height: 100px; /* 这里不加height或者设置min-height、max-height */ background-color: red;}.child { width: 100px; height: 200px; /* 把子元素高度从50px加到200px */ background-color: yellow;}
2)如下图所示,设置height属性之后,父元素高度不受子元素影响。

.parent { width: 200px; height: 100px; /* 这里设置height将父元素高度框死 */ background-color: red;}.child { width: 100px; height: 200px; /* 将子元素高度加到200px */ background-color: yellow;}
2. 上下相邻的块级元素
当两个垂直外边距相遇时,它们将形成一个外边距。合并后的外边距的高度等于两个发生合并的外边距的高度中的较大者。
magrin-bottom: 50px;
,下面盒子的margin-top: 40px;
,两个盒子之间的距离不是90px而是50px,同样也是取两者中的较大值。 
.parent { width: 200px; height: 100px; margin-bottom: 50px; /* 上面盒子的下边距为50px */ background-color: red;}.child { width: 100px; height: 50px; margin-top: 40px; /* 下面盒子的上边距为40px */ background-color: yellow;}
3. 空的块级元素
如果存在一个空的块级元素,border、padding、inline-content、height、min-height、max-height都不存在时,这个元素自己的上下外边距将会合并。即使设置了margin-top: 20px;
和margin-bottom: 20px;
,最终的边距仍为20px。
外边距合并的意义
外边距合并初看上去可能有点奇怪,但是实际上,它是有意义的。以由几个段落组成的典型文本页面为例。第一个段落上面的空间等于段落的上外边距。如果没有外边距合并,后续所有段落之间的外边距都将是相邻上外边距和下外边距的和。这意味着段落之间的空间是页面顶部的两倍。如果发生外边距合并,段落之间的上外边距和下外边距就合并在一起,这样各处的距离就一致了。
而根据w3c规范,两个margin是邻接的必须满足以下条件
4.1、必须是处于常规文档流(非float和绝对定位)的块级盒子,并且处于同一个BFC当中。
4.2、没有线盒,没有空隙(clearance,下面会讲到),没有padding和border将他们分隔开 4.3、都属于垂直方向上相邻的外边距,可以是下面任意一种情况: a: 元素的margin-top与其第一个常规文档流的子元素的margin-top b: 元素的margin-bottom与其下一个常规文档流的兄弟元素的margin-top c: height为auto的元素的margin-bottom与其最后一个常规文档流的子元素的margin-bottom d: 高度为0并且最小高度也为0,不包含常规文档流的子元素,并且自身没有建立新的BFC的元素的margin-top和margin-bottom避免边距合并
- 如果是空块元素上下外边距,只要div中有内容,会自行撑开,不会合并;
- 父元素设置了padding、border,不会发生合并;
- 改用上下内边距 (padding)代替上下外边距(margin)
- 在父元素内部形成一个 BFC
大家知道,在一个 BFC 中有两个特性,一是可以识别并包含浮动元素,另一个是两个相邻的块级盒子的垂直外边距会发生重叠。在上面的例子中,父元素和子元素都处于同一 BFC 中,导致它们的上下外边距发生了合并。解决的方案就是让父元素内部单独形成一个 BFC ,让父元素和子元素处于两个不同的布局环境中。那么怎样触发BFC?
- 根元素
- 父元素或者子元素设置了浮动(例如 float: left)
- 父元素或子元素的 position 为 absolute 或 fixed
- 父元素设置 display 为 flow-root(清除浮动)、inline-block(行内块元素)、table-cell、flex、inline-flex
- 父元素设置 overflow 为 hidden 、auto、scroll 等值(不为 visible)
在上面的例子中,给父元素设置 overflow: hidden; 并不是为了溢出隐藏,而是为了通过触发形成一个新的 BFC 解决同一 BFC 中上下外边距合并的问题
参考内容:
发表评论
最新留言
关于作者
