首页 前端知识 margin重叠问题及解决方案全览

margin重叠问题及解决方案全览

2024-06-01 10:06:37 前端知识 前端哥 235 775 我要收藏

Situation

项目中遇到了margin重叠问题,基于之前对这块知识掌握不熟练,所以学习之后在这里做一个总结吧。

Task

  • 了解margin重叠的种类
  • 学习不同重叠方式的解决方案
  • 总结

Action

是什么

margin重叠(又称margin塌陷):文档流内,块级元素与块级元素垂直方向上的 margin 合并(塌陷)为单个 margin,且只发生在垂直方向。
inline元素不存在margin 塌陷,因为inline元素不占有外边距,同样道理float元素也不存在margin合并。

为什么

很久很久以前是为了解决多文本段落最后一行排版的问题。
根据w3c规范,

  1. 必须处于常规文档流(不能是浮动和定位)的块级盒子,处于同一BFC当中
  2. 没有线盒,没有空隙,没有padding和border将其分割
  3. 都处于垂直方向相邻的外边距

相邻兄弟元素间

元素顶边与前面元素底边叠加
原理:相邻兄弟元素默认位于同一个块级上下文中
计算规则: 正正取大值,正负值相加,负负最小值

解决方案

BFC

我们知道BFC是隔离了的容器,所以BFC可以用来解决margin塌陷

  • 假设兄弟元素 A 和 B,可以使 A 的父元素触发 BFC,触发了 BFC 的父元素里面的 A 子元素不会在布局上影响到 B,自然不会有 margin 塌陷情况存在
  • 如果是父子嵌套的 margin 塌陷问题,只需要触发父元素的 BFC 即可
flex

导致margin塌陷代码原代码

<body>
    <style>
        .aa {
            flex-direction: column;
            width: 300px;
        }
        .bb {
            width: 200px;
            height: 200px;
            border: 1px solid #333;
            margin-top: 10px;
        }
    </style>
    <div class="aa">
        <div class="bb" style="margin-bottom: 10px;"></div>
        <div class="bb" style="margin-top: 10px;"></div>
    </div>
</body>

效果如下图所示,第一个子元素的margin-bottom未起作用
image.png
解决:父级元素flex布局,触发BFC,创建隔离的容器

<body>
    <style>
        .aa {
            display: flex;
            flex-direction: column;
            width: 300px;
        }
        .bb {
            width: 200px;
            height: 200px;
            border: 1px solid #333;
            margin-top: 10px;
        }
    </style>
    <div class="aa">
        <div class="bb" style="margin-bottom: 10px;"></div>
        <div class="bb" style="margin-top: 10px;"></div>
    </div>
</body>

两个元素的margin都乖乖生效了
image.png

浮动
<body>
    <style>
        .aa {
            border: 1px solid red;
        }
        .bb {
            width: 200px;
            height: 200px;
            border: 1px solid #333;
        }
    </style>
    <div class="aa">
        <div class="bb" style="margin-bottom: 10px;"></div>
        <div class="bb" style="margin-top: 10px;"></div>
    </div>
</body>

效果如下图所示,第一个子元素的margin-bottom未起作用
image.png
解决:子元素浮动定位,父元素清除浮动
image.png

空div

原代码

<body>
    <style>
        .aa {
            border: 1px solid red;
        }
        .bb {
            width: 200px;
            height: 200px;
            border: 1px solid #333;
        }
    </style>
    <div class="aa">
        <div class="bb" style="margin-bottom: 10px;"></div>
        <div class="bb" style="margin-top: 10px;"></div>
    </div>
</body>

上面元素margin失效
image.png
解决:修改代码,添加空div,设置为flex布局

<body>
    <style>
        .aa {
            border: 1px solid red;
        }
        .bb {
            width: 200px;
            height: 200px;
            border: 1px solid #333;
        }
    </style>
    <div class="aa">
        <div class="bb" style="margin-bottom: 10px;"></div>
        <div style="display: flex;"></div>
        <div class="bb" style="margin-top: 10px;"></div>
    </div>
</body>

正确效果显示:
image.png

父元素与第一/最后一个子元素间

原因:
a.margin-top 重叠

  1. 父元素非块状格式化上下文元素
  2. 父元素没有border-top设置
  3. 父元素没有padding-top值
  4. 父元素和第一个子元素之间没有inline元素分隔

b.margin-bottom 重叠

  1. 父元素非块状格式化上下文设置
  2. 父元素没有 border-bottom 设置
  3. 父元素没有 padding-bottom 值
  4. 父元素和第一个子元素之间没有inline元素分隔
  5. 父元素没有 height,min-height,max-height

计算规则: 子元素和父元素上边界重叠,以子元素的 margin-top 作为父元素的 margin-top 整体移动。对于 margin-bottom 同理

解决方案

父级加边框

原代码

<body>
    <style>
        .father {
            background-color: antiquewhite;
        }

        .child {
            margin-top: 30px;
            height: 200px;
            width: 200px;
            border: 1px solid #333;
        }
    </style>
    <div class="father">
        <div class="child">margin-top: 30px</div>
    </div>
</body>

效果如下所示
image.png
因此我们可以为父元素加上边框,改变它的大小,修改代码

<body>
    <style>
        .father {
            border: 1px solid red;
            background-color: antiquewhite;
        }

        .child {
            margin-top: 30px;
            height: 200px;
            width: 200px;
            border: 1px solid #333;
        }
    </style>
    <div class="father">
        <div class="child">margin-top: 30px</div>
    </div>
</body>

肉眼可见,margin-top生效~
image.png

父元素overflow:auto

原代码:

<body>
    <style>
        .father {
            background-color: green;
        }
    </style>
    <div class="father">
        <div style="margin-top: 30px;height: 200px; width: 200px;border: 1px solid #333;">margin-top: 30px</div>
    </div>
</body>

效果如下,依然未生效
image.png
修改我们的代码,为父元素加上overflow: auto;属性,创建BFC

<body>
    <style>
        .father {
            overflow: auto;
            background-color: green;
        }
    </style>
    <div class="father">
        <div style="margin-top: 30px;height: 200px; width: 200px;border: 1px solid #333;">margin-top: 30px</div>
    </div>
</body>

正确效果是~
image.png

父元素加上伪元素

原代码上菜

<body>
    <style>
        .father {
            background-color: antiquewhite;
        }
        .father::before {
            content: "";
            display: table;
        }
    </style>
    <div class="father">
        <div style="margin-top: 30px;height: 200px; width: 200px;border: 1px solid #333;">margin-top: 30px</div>
    </div>
</body>

老规矩,效果图紧随其上
image.png
解决:给父元素加一个伪元素
修改代码

<body>
    <style>
        .father {
            background-color: green;
        }
        .father::before {
            content: "";
            display: table;
        }
    </style>
    <div class="father">
        <div style="margin-top: 30px;height: 200px; width: 200px;border: 1px solid #333;">margin-top: 30px</div>
    </div>
</body>

生效~
image.png

flex布局/inline-block

原代码呈上:

<body>
    <style>
        .father {
            background-color: green;
        }
    </style>
    <div class="father">
        <div style="margin-top: 30px;height: 200px; width: 200px;border: 1px solid #333;">margin-top: 30px</div>
    </div>
</body>

image.png
解决:父亲元素flex布局或者设置行内块元素(inline-block)

<body>
    <style>
        .father {
            background-color: green;
            display: flex;
            /* display: inline-block; */
        }
    </style>
    <div class="father">
        <div style="margin-top: 30px;height: 200px; width: 200px;border: 1px solid #333;">margin-top: 30px</div>
    </div>
</body>

生效~
image.png

空block元素

原因:

  1. 元素没有 border 设置
  2. 元素没有 padding 值
  3. 里面没有 inline 元素
  4. 没有 height 或者min-height
解决方案

加上border/padding,加上高度

<body>
    <style>
        .box {
            border: 1px solid green;
            height: 100px;
            width: 100px;
            margin-top: 10px;
            margin-bottom: 20px;
        }
    </style>
    <div class="box"></div>
</body>

效果
image.png

Result

当静下心来认真写一篇blob还是很费时间的,按照神光的说法就是收获也会很大

  • effort processing,边思考变输出,也挺费力的,对技术掌握更深,比如本篇就帮助我对margin塌陷有个全面的理解
  • 心流,沉浸其中时间就过得很快
  • 抱着一步一步掌握的心态学习
  • 复利,将零散的知识串联起来
  • 影响力(这点我现在没有,惭愧,我还是会坚持输出自己的blob)
  • 社区反馈(目前努力的方向,希望可以和更多优秀的小伙伴讨论,从中学习)
  • 个人追求,我们经常看被人输出的文章,当自己灵感闪现的时候,若没有及时记录,后面想更深入了解点啥的时候,就记不起来了,我希望自己养成这个习惯,遇到了一个素材,尽量抽时间去产出一点什么东西,帮助自己理解思考

参考文档

为什么margin只会上下溢出/重叠而不会左右溢出/重叠?
MDN 外边距重叠
为什么我能坚持?因为写技术文章给我的太多了呀!

以上是blob全部内容,欢迎各位大佬指点~
🐇也祝大家元宵节快乐~~

转载请注明出处或者链接地址:https://www.qianduange.cn//article/10457.html
标签
评论
发布的文章

无涯教程-HTML5 - 表单标签

2024-06-08 00:06:06

HTML5基础2

2024-06-07 23:06:19

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!