margin 重叠问题 Margin Collapse

块的上外边距(margin-top)和下外边距(margin-bottom)有时合并(重叠)为单个边距,其大小为单个边距的最大值(或如果它们相等,则仅为其中一个),这种行为称为边距重叠。

MDN-外边距重叠

重叠的结果:

1、两个相邻的外边距都是正数时,重叠结果是它们两者之间较大的值。

2、两个相邻的外边距都是负数时,重叠结果是两者绝对值的较大值。

3、两个外边距一正一负时,重叠结果是两者的相加的和。

margin 重叠本质上的问题还是 BFC,要理解这个问题,我们先来看看重叠的条件。

重叠的条件

  • 必须是处于常规文档流(非 float 和绝对定位)的块级盒子,并且处于同一个 BFC 当中。
  • 没有线盒,没有空隙(clearance,下面会讲到),没有 padding 和 border 将他们分隔开
  • 都属于垂直方向上相邻的外边距,可以是下面任意一种情况
    • 元素的 margin-top 与其第一个常规文档流的子元素的 margin-top
    • 元素的 margin-bottom 与其下一个常规文档流的兄弟元素的 margin-top
    • height 为 auto 的元素的 margin-bottom 与其最后一个常规文档流的子元素的 margin-bottom
    • 高度为 0 或 auto 并且最小高度也为 0,不包含常规文档流的子元素,并且自身没有建立新的 BFC 的元素的 margin-top 和 margin-bottom

根据以上描述的条件,我们可以得出以下结论

  • 浮动元素不与任何元素的外边距产生重叠(包括其父元素和子元素)
  • 绝对定位元素不与任何元素的外边距产生重叠
  • 建立 BFC 的元素(例如浮动或 overflow 属性的值不为 visible)不会与其在流中的子元素的外边距重叠
  • inline-block 元素不与任何元素的外边距产生重叠
  • 一个常规文档流元素的 margin-bottom 与它下一个常规文档流的兄弟元素的 margin-top 会产生重叠,除非它们之间存在间隙(clearance)
  • 一个不包含 padding 和 border 的父元素的 margin-top 与其第一个不包含 clearance 子元素的 margin-top 产生重叠
  • 一个 'height' 为 'auto' 并且 'min-height' 为 '0'的常规文档流元素的 margin-bottom 会与其最后一个常规文档流子元素的 margin-bottom 重叠,条件为父元素不包含 padding 和 border ,子元素的 margin-bottom 不与包含 clearance 的 margin-top 重叠
  • 一个不包含border-top、border-bottom、padding-top、padding-bottom的常规文档流元素,并且其 'height' 为 0 或 'auto', 'min-height' 为 '0',其里面也不包含行盒(line box),其自身的 margin-top 和 margin-bottom 会重叠。

Collapsing margins

总结一下就是

  • 浮动元素、绝对定位、inline-block元素不与任何元素的外边距产生重叠
  • 不同 BFC 的元素不会产生重叠
  • 特殊情况下存在间隙(clearance)的元素不会产生重叠

我们来看看产生重叠的几种情况

相邻兄弟元素重叠

<div class="BFC">
<div class="middle-box margin red"></div>
<div class="middle-box margin green"></div>
</div>
<style>
.BFC{
display: flow-root;
}
.margin{
margin:20px;
}
.big-box{
width: 100px;
height: 100px;
}
.middle-box{
width: 50px;
height: 50px;
}
.red{
background-color: red;
}
.green{
background-color: green;
}
.blue{
background-color: blue;
}
</style>

效果如下图



我们通过absolute、inline-block、float可以使其margin不重叠







但是需要注意的是,使用absolute和float时,元素会脱离文档流,需要对其定位做相应处理。

另外,由于这两者脱离文档流之后,如果后面还有兄弟元素,这个兄弟元素仍然会与前一个元素邻接,也就是会继续产生 margin 重叠

<div class="BFC relative">
<div class="middle-box margin red"></div>
<div class="middle-box margin green" style="position:absolute;">absolute</div>
<div class="middle-box margin blue"></div>
</div>
<div class="BFC">
<div class="middle-box margin red"></div>
<div class="middle-box margin green" style="float: left">float</div>
<div class="middle-box margin blue"></div>
</div>

效果如下图



在这里就必须提一下经常与 float 一起出现的 clear 属性,这与我们上面提到的 间隙(clearance)也有关

clear 属性规定元素的哪一侧不允许其他浮动元素

描述
left 元素框的上外边界低于这个元素之前的任何左浮动框的下外边界
right 元素框的上外边界低于这个元素之前的任何右浮动框的下外边界
both 元素框的上外边界低于这个元素之前的任何左浮动框或右浮动框的下外边界
none 对浮动框没有限制

clear 属性设置了非 none 值后,就会产生间隙。这里摘抄文档中的原文,意思是间隙可以抑制重叠,并且充当元素的 margin-top

Values other than none potentially introduce clearance. Clearance inhibits margin collapsing and acts as spacing above the margin-top of an element. It is used to push the element vertically past the float.

看一个例子

<div class="BFC">
<div class="middle-box margin green" style="float: left">float</div>
<div class="middle-box margin blue" style="clear: both;"></div>
<div class="middle-box margin red"></div>
</div>

效果如下,由于元素的 margin-top 会与 float 元素的 margin-bottom 相接,间隙就是元素 margin-top 到 float 元素 margin-top 的距离



其实这里又隐式地产生了一个 margin 重叠,这不是套娃吗!

所以关于兄弟组件的 margin 重叠问题,还是建议用新建一个 BFC 的方式来解决。

上面 float 产生的重叠也可以用 BFC 来解决。

<div class="BFC">
<div class="middle-box margin red"></div>
<div class="BFC">
<div class="middle-box margin green"></div>
</div>
</div>

需要注意的是,建议新建 BFC 的时候使用 display:flow-root,意为创建一个行为类似于根元素的元素,这样语义化更好

父子元素 margin-top 重叠

<div class="BFC">
<div class="big-box margin green">
<div class="middle-box margin red"></div>
</div>
</div>

效果如下,子元素和父元素的 margin-top 重叠了



根据上面的总结,我们也可以在父子元素是上使用 inline-block、absolute、float 或在子元素上建立 BFC 来解决重叠问题

但这里提供一种更好的方式,设置父元素的 padding 或 border

<div class="BFC">
<div class="big-box margin green" style="padding: 10px">
<div class="middle-box margin red"></div>
</div>
</div>



这样父元素子元素的 margin 也就不会重叠了

另外,你可以在父元素中填充内容来制造间隙,可以使用::before 或 ::after 伪元素,不过这样会被内容占掉一部分的容器高度

<div class="BFC">
<div class="big-box margin green before">
<div class="middle-box margin red"></div>
</div>
</div>
<style>
.before::before{
content: '';
display: inline-block;
}
</style>



在实际使用中需要具体问题具体分析

auto 高度的父元素与子元素的 margin 重叠

<div class="BFC">
<div class="auto-box margin green">
<div class="middle-box margin red"></div>
</div>
</div>
<style>
.auto-box{
width: 100px;
height: auto;
}
</style>

效果如下

解决的方式和上面的思路类似,这里需要注意的就是由于父元素的高度是 auto,子元素脱离文档流的情况需认真考虑

仍然推荐在父元素中添加 border、padding 属性或在子元素上建立 BFC 的方式来解决这个问题

<div class="BFC">
<div class="auto-box margin green" style="border: 10px solid;">
<div class="middle-box margin red"></div>
</div>
</div>

在查阅资料中发现可以通过设置 min-height 来解决 margin 重叠,其实本质上只是把父元素的内容撑开了。

我个人认为这没有从根本上解决重叠的问题。

<div class="BFC">
<div class="auto-box margin green" style="min-height: 100px">
<div class="middle-box margin red"></div>
</div>
</div>

margin 重叠问题深入探究的更多相关文章

  1. 上下margin重叠传递问题

    我发现强迫症真的是我一个大病...每次都非得把所有情况都实验出来不可...BUT!!!!!!!!!悲催的是,这么多情况我根本记不住...还是要在写代码的时候不断出错再排错~受不了自己了!不过还是把这部 ...

  2. CSS 外边距(margin)重叠及防止方法

    边界重叠是指两个或多个盒子(可能相邻也可能嵌套)的相邻边界(其间没有任何非空内容.补白.边框)重合在一起而形成一个单一边界. 两个或多个块级盒子的垂直相邻边界会重合.结果的边界宽度是相邻边界宽度中最大 ...

  3. css margin重叠

    父子元素margin(垂直方向)重叠 解决办法: 给子元素添加浮动属性,相应父元素添加必要的清浮动属性: 给父元素添加边缘属性,如padding.border: 同级元素margin(垂直方向)反向重 ...

  4. 清浮动,防止上下margin重叠(浏览器顶部空白崩溃)

    清浮动 父级添加类别! .clearfix{zoom:1;//兼容ie6,7} .clearfix:after{ content:"."; display: "block ...

  5. CSS盒模型和margin重叠

    在 CSS 中,width 和 height 指的是内容区域的宽度和高度.增加内边距.边框和外边距不会影响内容区域的尺寸,但是会增加元素框的总尺寸.(div的实际占用尺寸变打了) 但: 一旦为页面设置 ...

  6. margin重叠

    margin重叠也就是我们常说的CSS 外边距合并,W3C给出如下定义: 外边距合并指的是,当两个垂直外边距相遇时,它们将形成一个外边距. 合并后的外边距的高度等于两个发生合并的外边距的高度中的较大者 ...

  7. margin重叠现象

    1.上下/左右相邻的普通元素margin,不是两者相加之和,而是取最大值,这个现象叫做margin重叠. 2. 普通元素才会发生margin重叠,如果是float元素,就不会发生.margin是两者相 ...

  8. 解决margin重叠的问题

    margin重叠有两种情况: 1.兄弟级的垂直块之间,margin这个属性上下边距,会发生重叠的情况 解决办法:float浮动或display:inline-block 2 .父子级的块之间,子级的上 ...

  9. 2016/2/25 1, margin auto 垂直方向测试 无效 2,margin重叠 3,哪些是块状哪些是内联 4,display:block inline 导航栏把内联转块状最常见+ 扩展

    1.利用margin auto完成首页居中,并自行研究,竖直方向用margin auto,是什么效果#container{width:1002px;margin: 0px auto;}    竖直方向 ...

随机推荐

  1. IDEA环境配置里的一些error

    1. idea添加edit configuration 没有tomcat图标 File->Setting->Build,Execution,Deployment-->Applicat ...

  2. DevOps Next-AI / ML虚拟会议

    这个中秋国庆,一起进阶反超呀!10月1日星期四,加入DevOps Next,可以参加有关AI和ML的免费活动,内容涉及持续测试,代码质量和DevOps生产力.优秀的你一起来加入! 关于本次活动 Dev ...

  3. centos7下安装MySQL 5.7.26 二进制版本(免安装绿色版)

    MySQL 5.7.26 二进制版本安装(免安装绿色版) 下载地址 https://downloads.mysql.com/archives/community/ https://cdn.mysql. ...

  4. Redis小记(一)

    1.redis的数据结构 (1)动态字符串(SDS) redis自身构建了一个简单动态字符串的抽象类型,SDS,在redis里,包含字符串的键值对在底层都是由SDS来实现的. 除了用来保存数据库的字符 ...

  5. Python练习题 037:Project Euler 009:毕达哥拉斯三元组之乘积

    本题来自 Project Euler 第9题:https://projecteuler.net/problem=9 # Project Euler: Problem 9: Special Pythag ...

  6. Arduino Mega 2560

    Arduino Mega 2560 www.theengineeringprojects.com/ 此板子有54个引脚,16个模拟量输入引脚,12个PWM输出引脚,4个串口,带I2C,SPI通讯口,更 ...

  7. 《穷查理年鉴》金钱 & 生意 & 律师(关于金钱)

    金钱 025.钱还得快才会借得快. 030.钱和人有着复杂的友谊:人能让钱变坏,钱也能让人变坏. 034.绝望增加债务,勤奋偿还债务. 037.只有一无所有的人才会没有烦恼. 049.穷人为他的胃找食 ...

  8. Jenkins从节点上构建自动化测试项目时报错:java.io.IOException: Unexpected termination of the channel

    在mac电脑上配置了Jenkins从节点,在该从节点上构建app UI 自动化测试项目,运行一些用例后报如下错误: java.io.EOFException at java.io.ObjectInpu ...

  9. thinkphp6.0.x 反序列化详记(一)

    前言 这几天算是进阶到框架类漏洞的学习了,首当其冲想到是thinkphp,先拿thinkphp6.0.x来学习一下,体验一下寻找pop链的快乐. 在此感谢楷师傅的帮忙~ 环境配置 用composer指 ...

  10. JSON,数组根据字段分组

    function GroupbyName(data, Name) { //data数据源,Name 根据什么字段分组 var map = {}, dest = []; for (var i = 0; ...