稀土掘金 稀土掘金

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

Situation

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

Task

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

Action

是什么

margin重叠(又称margin塌陷):文档流内,块级元素与块级元素垂直方向上的 margin 合并(塌陷)为单个 margin,且只发生在垂直方向。

inline元素不存在margin 塌陷,因为inline元素不占有外边距,同样道理float元素也不存在margin合并。

为什么

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

根据w3c规范,形成margin塌陷现象有几个条件

  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未起作用

解决: 父级元素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都乖乖生效了

浮动
<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未起作用

解决: 子元素浮动定位,父元素清除浮动

空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失效

解决:修改代码,添加空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>

正确效果显示:

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

原因:

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>

效果如下所示

因此我们可以为父元素加上边框,改变它的大小,修改代码

<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生效~

父元素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>

效果如下,依然未生效

修改我们的代码,为父元素加上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>

正确效果是~

父元素加上伪元素

原代码上菜

<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>

老规矩,效果图紧随其上

解决:给父元素加一个伪元素

修改代码

<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>

生效~

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>

解决:父亲元素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>

生效~

空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>

效果

Result

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

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

参考文档

为什么margin只会上下溢出/重叠而不会左右溢出/重叠?

MDN 外边距重叠

为什么我能坚持?因为写技术文章给我的太多了呀!

以上是blog全部内容,欢迎各位大佬指点~

🐇也祝大家元宵节快乐~~

玻璃钢生产厂家北京丰收女神玻璃钢雕塑广州商场美陈玻璃钢卡通雕塑价格江苏户外玻璃钢花盆湘西玻璃钢雕塑制作厂家江苏节庆商场美陈报价汕尾玻璃钢卡通雕塑加工厂家苏州玻璃钢仿真水果雕塑定制重庆玻璃钢雕塑去哪找玻璃钢雕塑漆怎么选保定正规玻璃钢雕塑全国发货江苏节庆商场美陈市场价甘南仿真人物玻璃钢雕塑订做复仇者联盟玻璃钢雕塑资料户外玻璃钢雕塑多少钱获嘉玻璃钢雕塑儿童玻璃钢雕塑公司白银户外玻璃钢雕塑哪家好兰州城市玻璃钢雕塑厂家耐腐蚀玻璃钢雕塑价格合理常州玻璃钢雕塑厂家直销玻璃钢锻铜雕塑厂家相山玻璃钢造型雕塑亳州创意玻璃钢雕塑哪家便宜河南花朵玻璃钢仿铜雕塑广平玻璃钢花盆花器沁阳玻璃钢花盆玻璃钢花盆学徒南宫玻璃钢雕塑装饰材料商场夏季美陈方案彭州玻璃钢门头雕塑香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化