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. 笨办法学Python3习题19

    学习笔记记录一下 def cheese_and_crackers(cheese_count, boxes_of_crackers): print (f"You have {cheese_co ...

  2. POI和easyExcel

    POI与easyExcel 这个东西一般用来做什么? 将用户信息导出为Excel表格(导出数据) 将Excel表中的信息录入到网站数据库(比如一些习题上传) 在开发过程中会遇到对Excel的处理,比如 ...

  3. 如何高雅的使用redis去获取一个值

    //场景,给定一个订单号来从缓存中查询一个订单信息; 步骤: 1从redis中直接获取,有数据就返回 2.如果redis中没有值,就查数据库 3.数据库查到的数据不为空,就刷到redis中 4.返回查 ...

  4. Python面向对象基础变量

    In [1]: class A: ...: NAME = 'A' # 类的直接下级作用域 叫做类变量 ...: def init(self, name): ...: self.name = name ...

  5. 64位Win7下H3C的iMC无法查看“网络拓扑”的解决方法、心路历程

    64位Win7下H3C的iMC无法查看"网络拓扑"的解决方法.心路历程

  6. 【题解】CF1375D Replace by MEX

    \(\color{purple}{Link}\) \(\text{Solution:}\) 观察到题目要求操作次数不超过\(2n,\)且不必最小化操作次数,所以一定是构造题. 考虑将序列转化为\([0 ...

  7. DX12龙书 01 - 向量在几何学和数学中的表示以及运算定义

    0x00 向量 向量 ( vector ) 是一种兼具大小 ( magnitude ) 和方向的量. 0x01 几何表示 几何方法中用一条有向线段来表示一个向量,其中,线段长度代表向量的模,箭头的指向 ...

  8. 深入理解Logger日志——框架绑定原理

    深入理解Logger日志--框架绑定原理 说到Logger日志的动态绑定,主要归功与Slf4j,在之前的文章也说过,Slf4j是类似于Apache Common-Logging,英文为Simple L ...

  9. Linux nginx 安装 启动

    nginx下载地址:https://nginx.org/download/ ## 解压 tar -zxvf nginx-1.9.9.tar.gz ##进入nginx目录 cd nginx-1.9.9 ...

  10. spring boot:用rocketmq发送延时消息用来取消订单(spring boot 2.3.3)

    一,为什么要用延时消息来取消订单? 1,为什么要取消订单 在电商的下单过程中,需要在生成订单时扣减库存, 但有可能发生这种情况:用户下了单,临时改变主意不再支付, 则订单不能无限期的保留,因为还要把占 ...