1.垂直外边距合并
我们先来看下面的代码:
/* 样式 */
<style>
.father {
width: 200px;
height: 200px;
border: 1px solid;
background-color: aqua;
}
.son {
width: 100px;
height: 100px;
background-color: #0f0;
margin-top: 100px;
}
</style>
/* 布局 */
<div class="father">
<div class="son"></div>
</div>
代码中给了 .father 宽200px、高200px; .son 宽100px、高100px。并且 .son 有一个上外边距margin-top: 100px;
(同时为了便于观察,给body加上上边框:border-top: 1px solid;)
理想情况下的 .son 的位置应该是在 .father 父元素的左下角。并且 .father贴紧body上边缘。
但实际上的情况是:
我们可以看到,子元素 .son 的相对于 .father 的位置并末发生变化,而是父元素 .father 的位置发生改变,就像是 .son 的 margin-top属性值给到了 .father.
这种现象就是我们所说的垂直外边距合并,也称元素跨界,相邻父子元素中子元素的上外边距传递给了父元素,发生的条件有两个: 1.父子元素 2.相邻
父子垂直外边距合并的情况会影响到我们对页面的布局,所以必须要处理。
解决的方案:
- 把子元素的 margin-top 换成父元素的 padding-top,但是在这种方案中,padding会撑开父元素的盒子大小,从而引起一些不必须要的麻烦。(不用)
- 给父元素一个 border-top值,指定元素的上边界,从而子元素的 margin-top 就不会越过这个边界。但这种方案同样会影响父元素的盒子大小。(不用)
- 给父元素设置 overflow属性,开启BFC,让父元素成为一个在页面中独立的盒子,因而盒子内部的布局变不会影响到盒子外部的布局。(可选)
- 使用伪元素before,在父元素中添加伪元素::before,使父元素和子元素之间不相邻,自然就不会发生外边距合并。(可选)
.father::before {
content: '';
display: table;
}
2.浮动的高度塌陷
浮动的高度塌陷就不多说的,原因是不在文档流(脱离文档流)的元素无法撑开在文档流中的父元素的高度。是在我们使用浮动布局中常出现并且要解决的现象。
解决的方案:
- 给父元素加overflow属性; 原理是BFC (计算BFC的高度时,浮动元素也参与计算).
- 给子元素加both属性。以清除浮动带来的影响。
- 使用伪元素after作用于父元素。并给伪元素添加 clear属性清除浮动带来的影响。原理是位于浮动元素下方文档流中的元素会占用上方浮动元素的位置,从而重叠(文档流中的元素在下层,浮动元素在文档流的上方,使用 clear属性可以清除这个影响,让原本位于浮动元素下方文档流中的元素就位于那。
.father::after {
content: '';
display: table;
clear: both;
}
如果对于方案3不理解,可以看看下面的图解过程:
a.初始状态, .son 并末撑开父元素 .father;
/* 样式 */
<style>
body {
border-top: 1px solid;
}
.father {
width: 100px;
border: 1px solid;
}
.son {
width: 100px;
height: 100px;
background-color: #0f0;
float: left;
}
/* .father::after {
content: '';
display: table;
clear: both;
} */
</style>
/* 布局 */
<div class="father">
<div class="son"></div>
</div>
b.添加伪元素after,父元素还是末被撑开
/* 样式 */
<style>
body {
border-top: 1px solid;
}
.father {
width: 100px;
border: 1px solid;
}
.son {
width: 100px;
height: 100px;
background-color: #0f0;
float: left;
}
.father::after {
content: '';
display: table;
/* clear: both; */
}
</style>
/* 布局 */
<div class="father">
<div class="son"></div>
</div>
c.添加 clear属性
/* 样式 */
<style>
body {
border-top: 1px solid;
}
.father {
width: 100px;
border: 1px solid;
}
.son {
width: 100px;
height: 100px;
background-color: #0f0;
float: left;
}
.father::after {
content: '';
display: table;
clear: both;
}
</style>
/* 布局 */
<div class="father">
<div class="son"></div>
</div>
可以看到,父元素border被撑开。
3.子元素溢出
子元素的高度或者宽度超出了父元素范围,如下:
/* 样式 */
<style>
body {
border-top: 1px solid;
}
.father {
width: 100px;
height: 100px;
border: 2px solid;
}
.son {
width: 150px;
height: 100px;
background-color: #0f0;
}
</style>
/* 布局 */
<div class="father">
<div class="son"></div>
</div>
可使用 overflow: hidden隐藏子元素在父元素中溢出的部分。
/* 样式 */
<style>
body {
border-top: 1px solid;
}
.father {
width: 100px;
height: 100px;
border: 2px solid;
/* 处理溢出部分的样式,可选值有:
autovisible. 默认值,子元素溢出在父元素外部显示。
hidden. 溢出内容将会被裁剪不会显示。
scroll. 生成滚动条。通过滚动条来查看完整内容。
auto. 根据溢出部分生成滚动条。 */
overflow: hidden;
}
.son {
width: 150px;
height: 100px;
background-color: #0f0;
}
</style>
/* 布局 */
<div class="father">
<div class="son"></div>
</div>
使用了定位的元素同样会溢出, 也可以使用overflow: hidden隐藏。
.father {
width: 100px;
height: 100px;
border: 2px solid;
/* overflow: hidden; */
position: relative;
}
.son {
width: 150px;
height: 100px;
background-color: #0f0;
position: absolute;
}
综上,我们可以使用伪元素before来处理垂直外边距合并的问题,使用伪元素after来处理浮动的高度塌陷问题。同时,我们可以将这两种方法写到一起,达到 处理浮动的高度塌陷的同时,又可以解决垂直外边距的合并。
/* 清除浮动的高度塌陷 和 解决外边距合并 */
.clearfix::before,
.clearfix::after {
content: '';
display: table;
clear: both;
}
并且在需要的时候将类名添加使用,如下:
/* 样式 */
<style>
.father {
width: 200px;
height: 200px;
background-color: aqua;
}
.son {
width: 100px;
height: 100px;
background-color: #0f0;
/* 垂直外边距合并 */
margin-top: 100px;
}
/* 清除浮动的高度塌陷和外边距合并的公共样式 */
.clearfix::before,
.clearfix::after {
content: '';
display: table;
clear: both;
}
</style>
/* 布局 */
<div class="father clear"> /* 添加clear类名解决 */
<div class="son"></div>
</div>
可能有的小伙伴会觉得这个方法不如overflow: hidden来的方便,因为overflow: hidden也可以同时解决浮动的高度塌陷和垂直外边距合并。
但是,overflow: hidden在一些特定的场景下会有一些副作用。
比如使用了position: absolute的子元素在父元素中溢出时,如果这时候使用overflow: hidden;就会使溢出部分隐藏。
如果我们即不想让子元素在父元素中的溢出部分隐藏,又想解决浮动或者外边距合并的问题,那么这时候就不能在父元素中使用overflow: hidden了。而应该使用伪元素来处理更为恰当。
如下所示,我们想让浮动的子元素撑开父元素的高度
/* 样式 */
<style>
.father {
width: 200px;
height: 100px;
border: 2px solid #000;
position: relative;
}
.son {
width: 100px;
height: 100px;
float: left;
}
.son1 {
background-color: #f00;
}
.son2 {
background-color: #00f;
}
span {
width: 250px;
height: 10px;
position: absolute;
top: 0;
left: 0;
background-color: #0f0;
}
</style>
/* 布局 */
<div class="father">
<div class="son son1"></div>
<div class="son son2"></div>
<span></span>
</div>
如果使用给 .father添加 overflow: hidden;子元素span溢出的部分将隐藏。
而使用伪元素处理就不会隐藏溢出的部分
/* 样式 */
<style>
.father {
width: 200px;
height: 100px;
border: 2px solid #000;
position: relative;
}
.son {
width: 100px;
height: 100px;
float: left;
}
.son1 {
background-color: #f00;
}
.son2 {
background-color: #00f;
}
span {
width: 250px;
height: 10px;
position: absolute;
top: 0;
left: 0;
background-color: #0f0;
}
.clearfix::before,
.clearfix::after {
content: '';
display: table;
clear: both;
}
</style>
/* 布局 */
<div class="father clearfix">
<div class="son son1"></div>
<div class="son son2"></div>
<span></span>
</div>
我们可以将这个类的样式放入公共样式中,不仅可以有效果地解决问题,也可减少CSS的代码量。