Situation
项目中遇到了margin重叠问题,基于之前对这块知识掌握不熟练,所以学习之后在这里做一个总结吧。
Task
- 了解margin重叠的种类
- 学习不同重叠方式的解决方案
- 总结
Action
是什么
margin重叠(又称margin塌陷):文档流内,块级元素与块级元素垂直方向上的 margin 合并(塌陷)为单个 margin,且只发生在垂直方向。
inline元素不存在margin 塌陷,因为inline元素不占有外边距,同样道理float元素也不存在margin合并。
为什么
很久很久以前是为了解决多文本段落最后一行排版的问题。
根据w3c规范,
- 必须处于常规文档流(不能是浮动和定位)的块级盒子,处于同一BFC当中
- 没有线盒,没有空隙,没有padding和border将其分割
- 都处于垂直方向相邻的外边距
相邻兄弟元素间
元素顶边与前面元素底边叠加
原理:相邻兄弟元素默认位于同一个块级上下文中
计算规则: 正正取大值,正负值相加,负负最小值
解决方案
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 重叠
- 父元素非块状格式化上下文元素
- 父元素没有border-top设置
- 父元素没有padding-top值
- 父元素和第一个子元素之间没有inline元素分隔
b.margin-bottom 重叠
- 父元素非块状格式化上下文设置
- 父元素没有 border-bottom 设置
- 父元素没有 padding-bottom 值
- 父元素和第一个子元素之间没有inline元素分隔
- 父元素没有 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元素
原因:
- 元素没有 border 设置
- 元素没有 padding 值
- 里面没有 inline 元素
- 没有 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
当静下心来认真写一篇blob还是很费时间的,按照神光的说法就是收获也会很大
- effort processing,边思考变输出,也挺费力的,对技术掌握更深,比如本篇就帮助我对margin塌陷有个全面的理解
- 心流,沉浸其中时间就过得很快
- 抱着一步一步掌握的心态学习
- 复利,将零散的知识串联起来
- 影响力(这点我现在没有,惭愧,我还是会坚持输出自己的blob)
- 社区反馈(目前努力的方向,希望可以和更多优秀的小伙伴讨论,从中学习)
- 个人追求,我们经常看被人输出的文章,当自己灵感闪现的时候,若没有及时记录,后面想更深入了解点啥的时候,就记不起来了,我希望自己养成这个习惯,遇到了一个素材,尽量抽时间去产出一点什么东西,帮助自己理解思考
参考文档
为什么margin只会上下溢出/重叠而不会左右溢出/重叠?
MDN 外边距重叠
为什么我能坚持?因为写技术文章给我的太多了呀!
以上是blob全部内容,欢迎各位大佬指点~
🐇也祝大家元宵节快乐~~