清除浮动 + BFC

浮动

1.场景

我们想实现如下效果,肯定会想到float或者flex,flex先不做讨论

你想象的浮动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div class="box">
<div class="left"></div>
<div class="right"></div>
</div>

.box {
border: 1px solid black;
padding: 5px;
width: 450px;
}
.left {
width: 100px;
height: 100px;
background-color: red;
float: left;
}
.right {
width: 100px;
height: 100px;
background-color: red;
float: right;
}

实际上的浮动

2.寻找原因

原因是,浮动的元素会脱离文档流,父元素就无法管到他,布局也会往前推进,就会出现父元素高度坍塌的现象

这时候就需要清除浮动

1. 将父级也设置成浮动

1
2
3
4
5
6
.box{
border: 1px solid #000;
padding: 5px;
width: 450px;
float: left;
}

缺点: 这种方法肯定是弊大于利,想想父级设置成浮动了,爷爷级又管不到父级了,又得解决爷爷级的高度坍塌,这不是无限套娃?

2.给父级增加定位absolute

1
2
3
4
5
6
.box{
border: 1px solid #000;
padding: 5px;
width: 450px;
position: absolute;
}

缺点: position:absolute也会脱离文档流,影响了整体布局

3.给父级设置 overflow:hidden

1
2
3
4
5
6
7
8
.box{
border: 1px solid #000;
padding: 5px;
width: 450px;
overflow:hidden;
letter-spacing: 10px;
/* word-break: break-all; */
}

缺点:当文本过长,且包含过长英文时,会出现英文文本被隐藏的情况

1
2
3
4
5
<div class="box">
<div class="left"></div>
<div class="right"></div>
<div>张三张三张三张三张三张三张三张三张三张三张三张三张三张三张三张三张三张三ahdhjfsahdhjfagahdhjfagghadsfghhgafghjafjgfdgasjgfsahdhjfagghadsfghhgafghjafjgfdgasjgfsghadsfghhgafghjafjgfdgasjgfs张三张三张三张三张三张三张三张三张三张三张三张三张三张三张三张三张三</div>
</div>

文字被隐藏

4.给父级设置对应的高度

1
2
3
4
5
6
.box {
border: 1px solid black;
padding: 5px;
width: 450px;
height: 100px
}

缺点:如果浮动元素是定高的,那还好,如果是不定高的,那这种方式就很不灵活了,有可能今天是100px,明天是200px,后天是300px,那你不是得累死?

5.末尾增加空元素进行clear

关于clear:

描述
left 在左侧不允许浮动
right 在右侧不允许浮动
both 在左右两侧均不允许浮动
none 默认值。允许浮动元素出现在两侧
inherit 规定应该从父元素继承 clear 属性的值

所以这里bottomDiv设置成clear:both,代表了它左右都不能有浮动元素,这迫使了他往下移动,进而撑开了父级盒子的高度。

1
2
3
4
5
6
7
8
9
<div class="box">
<div class="left"></div>
<div class="right"></div>
<div class="bottomDiv"></div>
</div>

.bottomDiv {
clear: both;
}

缺点:增加了一个div标签,增加了页面的渲染负担

6.给父级添加微元素进行clear

这种方法就是用伪元素代替了上面的div标签,大家都知道,伪元素是不会被渲染出来的,所以也很好的弥补了上一种方法的缺点。

1
2
3
4
5
6
.box::after {
content: '.';
height: 0;
display: block;
clear: both;
}

BFC

1.官网解释

块格式化上下文(Block Formatting Context,BFC)是web页面可视化css渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。浏览器对BFC的限制规则是:

  1. 生成BFC元素的子元素会一个接一个的放置
  2. 垂直方向上他们的起点是一个包含块的顶部,两个相邻元素之间的垂直距离取决于元素的margin特性。在BFC中相邻的块级元素的外边距会折叠(Mastering margin collapsing)
  3. 生成BFC元素的子元素中,每一个子元素左外边距与包含块的左边界相接触(对于从右到左的格式化,右外边距接触右边界),即使浮动元素也是如此(尽管子元素的内容区域会由于浮动而压缩),除非这个子元素也创建了一个新的BFC(如它自身也是一个浮动元素)

2.触发条件

  • 根元素,即HTML标签
  • 浮动元素:float值为left、right
  • overflow值不为visible,为auto、scroll、hidden
  • display值为inline-block、table-cell、table-caption、table、inline-table、flex、inline-flex、--grid、inline-grid
  • 定位元素:position值为absolute、fixed

3.个人理解

  1. 内部的Box会在垂直方向上一个接一个的放置
  2. 内部的Box垂直方向上的距离由margin决定(属于同一个BFC的两个相邻Box的margin会发生折叠,不同BFC不会发生折叠)
  3. 每个元素的左外边距与包含块的左边界相接触(从左向右),即使浮动元素也是如此(BFC中子元素不会超出他的包含块,而position为absolute的元素可以超出他的包含块边界)
  4. BFC的区域不会与float的元素区域重叠
  5. 计算BFC的高度时,浮动子元素也参与计算

1点和第3点就不用说了,大家都懂,下面就来着重说说第2,4,5点吧!

解决margin重叠问题

假如我想要两个盒子间距20px,我这么写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div class="box2"></div>
<div class="box3"></div>

.box2 {
margin-bottom: 10px;
width: 100px;
height: 100px;
background-color: red;
}

.box3 {
margin-top: 10px;
width: 100px;
height: 100px;
background-color: red;
}

结果发现,并没有达到预期,两个盒子的margin重叠了:

margin重叠

怎么解决呢?根据个人理解里的第2点可知:两个不同BFC环境的盒子,他们两的margin才不会重叠,那么我们只需触发box3的BFC就行

1
2
3
4
5
6
7
.box3 {
margin-bottom: 10px;
width: 100px;
height: 100px;
background-color: red;
float: left;
}

这就实现了两个盒子中键间隔20px了

触发box3的BFC

浮动元素与BFC盒子不重叠

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div class="box2 w"></div>
<div class="box3 w"></div>

.w {
width: 100px;
height: 100px;
}

.box2 {
float: left; // 触发BFC
background: red;
}

.box3 {
background: green;
}

结果是,因为红色盒子浮动脱离文档流,导致绿色盒子向前推进,导致红色盒子盖住了绿色盒子

box2触发了BFC

怎么解决呢?根据个人理解里的第4点可知:float盒子与BFC盒子不重叠,所以我们只需要把绿色盒子设置为BFC盒子就行

1
2
3
4
.box3 {
background: green;
overflow:hidden // 触发BFC
}

box3也触发BFC

利用BFC清除浮动

根据个人理解里的第5点可知:BFC盒子会把内部的float盒子算进高度中,这也是为什么前面可以通过给父级盒子设置float: left position: absolute overflow: hidden来解决浮动的高度塌陷问题,因为这些做法都使父级盒子变成一个BFC盒子,而BFC盒子会把内部的float盒子算进高度,顺势解决了高度塌陷问题