你不一定知道的css知识——margin不重叠的情形

margin重叠

摘自css2.1规范中文版

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

margin重叠的计算规则

摘自css2.1规范中文版

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

什么是相邻的margin

摘自css2.1规范中文版
两个margin是相邻的,当且仅当:

  • 都属于流内块级盒,处于同一个块格式化上下文。
  • 没有行盒(line box),没有空隙,没有padding并且没有border把它们隔开(注意,因此某些0高度行盒)
  • 都属于竖直相邻盒边(vertically-adjacent box edges),即来自下列某一对:
    1.一个盒的top margin和它的第一个流内子级的top margin
    2.一个盒的bottom margin和它的下一个流内后面的兄弟(its next in-flow following sibling)的top margin
    3.最后一个流内子级的bottom margin和它的父级的bottom margin,如果父级的高度的计算值为'auto'
    4.一个盒的top和bottom margin,该盒没有建立一个新的块格式化上下文并且min-height的计算值为0,height的计算值为0或者'auto',并且没有流内子级

如果一个margin的任何部分margin与另一个margin相邻的话,就认为它与那个margin相邻,是合并(collapsed)margin。

具体分析各个条件

1.都属于流内块级盒,处于同一个块格式化上下文。

什么是流内元素?如果一个元素是浮动的,绝对定位的或者是根元素,那么它就是流外元素。如果一个元素不是流外的,就叫流内元素。
流内块级盒,就是流内块级元素生成的一个盒。

结论1:根元素的盒子margin不会发生重叠(原因:根元素虽然是块级盒,但不是流内元素)。

举个🌰:根元素与body的margin不会重叠

 html {margin-top:10px;}
 body {margin-top:10px;}

事实:body距离视口顶部20px。

结论2: 任何浮动的、绝对定位的盒子不会与任何其他盒子的margin合并(原因:它们是流外块级盒)。

举个🌰:两个绝对定位的盒子,不会发生margin重叠。

<style>
    .div1 {
        width: 100px;
        height: 100px;
        position: absolute;
        background: red;
        margin-bottom: 10px;
        top: 0;
    }

    .div2 {
        width: 100px;
        height: 100px;
        position: absolute;
        background: yellow;
        margin-top: 10px;
        top: 100px;
    }
</style>
    <div class="div1"></div>
<div class="div2"></div>

在浏览器一看,咦,两个div间距刚好是10px,这不是发生margin重叠了吗?no,no,no。如果此时,改变其中一个div的margin值,都不会影响任何一个div的布局。通俗的讲就是,把绝对定位的盒子比作飞起来的盒子,那么这两个飞起来的盒子,一定处于不同高度,因此,不管这个盒子如何移动,都不会影响任何一个飞起来的盒子。

什么是格式化上下文? 常规流中的盒属于一个格式化上下文,可能是块或是内联,但不能都是(既是块又是内联)。块级盒参与块格式化上下文。内联级盒参与内联格式化上下文 。

新建块级格式化上下文(BFC)的条件

  • 浮动元素,float除了none以外的值。
  • 绝对定位元素,position(absolute,fixed)
  • display 为以下其中之一的值 inline-blocks,table-cells,table-captions
  • overflow 除了 visible 以外的值(hidden,auto,scroll)
  • 注意:"display:table" 本身并不产生 BFC,而是由它产生匿名框,匿名框中包含 "display:table-cell" 的框会产 BFC。

在一个块格式化上下文中,盒在竖直方向一个接一个地放置,从包含块的顶部开始。两个兄弟盒之间的竖直距离由margin属性决定。同一个块格式化上下文中的相邻块级盒之间的竖直margin会合并。

结论3:建立了新的块级格式化上下文的元素的margin不会与它们的流内子集合并。(原因:不在同一个块级格式化上下文)

举个🌰:overflow不为‘visible’的元素,不会与它的流内子级合并。

.father {
    width: 100px;
    height: 100px;
    background: red;
    margin-top: 10px;
 }
 .child {
    width: 50px;
    height: 50px;
    background: yellow;
    margin-top: 20px;
 }
<div class="father">
  <div class="child"></div>
</div>

这种情况是,father的overflow是‘visible',发生了margin重叠,father向下偏移20px,如下图所示。


overflow不为‘visible’的元素,不会与它的流内子级合并

如果把father的overflow的值改为不是‘visible'的值,那么就不会发生margin重叠,如下图所示。

overflow不为‘visible’的元素,不会与它的流内子级合并

2.没有行盒(line box),没有空隙,没有padding并且没有border把它们隔开。

意思就是说,如果两个margin之间有东西隔着,它们并不是紧挨着一起,那么就不会发生margin重叠。

举个🌰:父元素有border,父子元素不会发生margin重叠。

  <style>
 .father{
    width: 100px;
    height: 100px;
    background: red;
    margin-top: 10px;
 }
 .child {
    width: 100px;
    height: 50px;
    background: yellow;
    margin-top: 20px;
 }
</style>

<div class="father">
<div class="child"></div>
</div>

这种情况是,父子元素margin没有被隔开的。因此,margin重叠了。如图所示:


父元素有border,父子元素不会发生margin重叠

如果给父元素顶部添加1像素的border,那么父子元素margin被边框隔离,此时不会发生margin重叠。如图所示:

父元素有border,父子元素不会发生margin重叠

此时child距离father顶部20px;

在举个例子:空div的margin自身重叠

  <style>
    .div1 {
        width: 100px;
        margin-top: 100px;
        margin-bottom: 100px;
    }
    .div2 {
        width: 100px;
        height: 100px;
        background: red;
    }
</style>
<div class="div1">
</div>
<div class="div2"></div>

如果空div的上下margin没有隔开,就会发生重叠,如图所示:


空div的margin自身重叠

红色div向下偏离了100px,而不是200px,因为空div发生了margin重叠。如果给空div加上padding-top=10px,就不会发生margin重叠,如图所示:

空div的margin自身重叠

此时红色div向下偏移了210px(100+100+10)。

3.最后一个流内子级的bottom margin和它的父级的bottom margin,如果父级的高度的计算值为'auto'。

  <style>
    .father {
        width: 100px;
        margin-bottom: 100px;
    }
    .child {
        width: 100px;
        height: 100px;
        margin-bottom: 150px;
        background: red;
    }
    .sibling {
        width: 100px;
        height: 100px;
        background: yellow;
    }
</style>
<div class="father">
    <div class="child"></div>
</div>
<div class="sibling"></div>

此时father元素高度是auto,father的margin-bottom与child的margin-bottom,发生了重叠,因此,sibling距离father150px;
如图所示:

最后一个流内子级的bottom margin和它的父级的bottom margin,如果父级的高度的计算值为'auto'。

如果此时给father设置height:100px;那么father的margin-bottom就不会和child的margin-bottom发生重叠。此时sibling与father的垂直距离,只跟它们的margin值有关,与child的margin值无关。如图所示:

最后一个流内子级的bottom margin和它的父级的bottom margin,如果父级的高度的计算值为'auto'。

4.一个盒的top和bottom margin,该盒没有建立一个新的块格式化上下文并且min-height的计算值为0,height的计算值为0或者'auto',并且没有流内子级。

   <style>
    .div1 {
        width: 100px;
        margin-top: 100px;
        margin-bottom: 100px;
    }

    .div2 {
        width: 100px;
        height: 100px;
        background: red;
    }
</style>
<div class="div1">
</div>
<div class="div2"></div> 

这种情况下,div1没有建立一个新的格式化上下文并且height:auto,也没有流内子级。div1自身div就重叠了,div2便宜100px。如图所示:


一个盒的top和bottom margin,该盒没有建立一个新的块格式化上下文并且min-height的计算值为0,height的计算值为0或者'auto',并且没有流内子级。

如果将div1的overflow设置为’不为visible'的值,或添加流内子级<span>1</span>(不能是空标签,否则margin照样重叠),或添加height值。此时,margin都不会重叠。这个就不贴图片了。

总结

把margin重叠的条件分析了一遍,就得到了margin不重叠的情况。
我的总结是:只要两个margin被隔开了,就一定不会发生margin重叠。可以是上下border隔开,可以是被上下padding隔开,也可以是被高度隔开,可以是被流内子级隔开,可以被空隙(空隙的产生与clear有关)隔开,可以被新建立的格式化上下文隔开。
以下是css2.1规范的总结

  • 一个浮动的盒与任何其它盒之间的margin不会合并(甚至一个浮动盒与它的流内子级之间也不会)
  • 建立了新的块格式化上下文的元素(例如,浮动盒与overflow不为'visible'的元素)的margin不会与它们的流内子级合并
  • 绝对定位的盒的margin不会合并(甚至与它们的流内子级也不会)
  • 内联盒的margin不会合并(甚至与它们的流内子级也不会)
  • 一个流内块级元素的bottom margin总会与它的下一个流内块级兄弟的top margin合并,除非兄弟有空隙
  • 一个流内块级元素的top margin会与它的第一个流内块级子级的top margin合并,如果该元素没有top border,没有top padding并且该子级没有空隙
  • 一个'height'为'auto'并且'min-height'为0的流内块级盒的bottom margin会与它的最后一个流内块级子级的bottom margin合并,如果该盒没有bottom padding并且没有bottom border并且子级的bottom margin不与有空隙的top margin合并
  • 盒自身的margin也会合并,如果'min-height'属性为0,并且既没有top或者bottom border也没有top或者bottom padding,并且其'height'为0或者'auto',并且不含行盒,并且其所有流内子级的margin(如果有的话)都合并了。
    如果盒的top和bottom margin相邻,那么可能会被彻底合并(collapse through)
    margin。此时,元素的位置取决于与其它margin被合并了的元素的关系
    如果该元素的margin与其父级的top margin合并了,盒的top border边被定义为与其父级的相同
    否则,要么该元素的父级没有参与margin合并,要么只涉及其父级的bottom margin。如果该元素的bottom border不为0的话,其top border边的位置将正常显示(the same as it would have been)。
    注意,已被彻底合并了的元素的位置不影响其它margin被合并的元素的位置,只有在布局这些元素的后代时,才需要top border边的位置。

好了margin不重叠的分析就到此结束,如有错误,欢迎指出。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 198,932评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,554评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 145,894评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,442评论 1 268
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,347评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,899评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,325评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,980评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,196评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,163评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,085评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,826评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,389评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,501评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,753评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,171评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,616评论 2 339

推荐阅读更多精彩内容

  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,719评论 1 92
  • •前端面试题汇总 一、HTML和CSS 21 你做的页面在哪些流览器测试过?这些浏览器的内核分别是什么? ...
    Simon_s阅读 2,219评论 0 8
  • 作者:[zhengkonghong](https://coding.net/u/zhengkenghong) 本文...
    CODING_博客阅读 775评论 1 6
  • 本篇讲解的是主要是BFC 可以解决的 margin 重叠问题 ,如对你有帮助 ,请点个赞给个鼓励,谢谢~ 先来一张...
    DemonGao阅读 714评论 0 1
  • 1.浮动元素有什么特征?对父容器、其他浮动元素、普通元素、文字分别有什么影响? 何谓浮动元素?有什么特征?所谓浮动...
    草鞋弟阅读 807评论 0 1