CSS神器之一——块级格式化上下文BFC
块级格式化上下文(Block Formatting Context),简称BFC。BFC是一块独立的渲染区域,它规定了在该区域中,常规流块盒的布局。
这是一个非常重要的知识点,无论是项目页面的布局,还是和同事之间的交流,也或者是面试前端工程师,这都是经常会碰到的。
在这里补充常规流块级盒模型的相关知识:
- 在水平方向上,必须撑满包含块
- 在包含块的垂直方向上依次摆放
- 若外边距无缝相邻,则进行外边距合并
- 注意:常规流盒模型的自动高度和摆放位置,会忽视浮动元素,浮动元素在这里不展开描述
1、BFC概述
前面我们讲到,BFC会创建一个独立的渲染区域。那么,这些区域是如何创建的?这个区域是由某一个HTML元素创建,在以下的三种情况会在其内部产生BFC:
- 根元素,也就是说元素实际上也创建了BFC区域,覆盖率网页中的所有元素
- 浮动和绝对定位,这两者都是脱离文档流的
- overflow属性值部位visible的块级盒模型
接着,我们来看一张图,这张图里的元素有父子关系,我们来分析这些元素是由什么情况下产生的BFC。
看看大家猜对了吗?分析结果如下:
这个布局里,产生了四个BFC区域:
- 根元素创建的BFC,包含A, B, E, F, G
- 元素A创建的BFC,也就是B
- 元素C创建的BFC,也就是D
- 元素G创建的BFC,也就是H
2、BFC的使用规则
- 不同的BFC区域,进行渲染的时候互不干扰
- 创建BFC的元素,内部和外部的渲染互不影响。换句话说,BFC的产生隔绝了内部和外部的联系。下面详细讲解具体规则。
(1)创建BFC的元素,它的自动高度需要计算浮动元素
元素塌陷问题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.container {
background: rgb(170, 158, 158);
}
.item {
float: left;
width: 200px;
height: 200px;
margin: 10px;
background: rgb(118, 169, 235);
}
</style>
</head>
<body>
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</body>
</html>
我们希望container能够自动撑开,有背景色,但是当我们在浏览器打开的时候却发现,背景并没有出来:
打开控制台,我们发现container的高度居然是0???这么骚???这其实就是著名的元素塌陷问题,常规流元素会自动忽视浮动元素,在我们的代码里,它认为盒子内部并没有其他元素,所以高度为0。
那么,我们应该怎么解决呢?非常简单,我们只需要让元素塌陷的div创建BFC就可以了,因为创建BFC的元素会自动计算浮动元素的高度。其中,采用overflow: hidden的副作用最小,关键代码如下:
.container {
background: rgb(170, 158, 158);
/* 前两种方式会改变布局 */
/* position: absolute;
float: left; */
/* 副作用最小 */
overflow: hidden;
}
.item {
float: left;
width: 200px;
height: 200px;
margin: 10px;
background: rgb(118, 169, 235);
}
但是副作用最小的方法一定适用所有情况吗?显然不是,如果仅仅为了解决高度坍塌,建议直接清除浮动。因为在有些时候,我们可能需要解决溢出显示问题,那么overflow显然不是一个好办法。如下为清除浮动的代码:
.clearfix{
}
在学习BFC之前,我们会暴力地使用额外的子元素把盒子撑开,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
<style>
.container {
background: rgb(170, 158, 158);
}
.clearfix::after{
content: "";
display: block;
clear: both;
}
.item {
float: left;
width: 200px;
height: 200px;
margin: 10px;
background: rgb(118, 169, 235);
}
</style>
</head>
<body>
<div class="container clearfix">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</body>
</html>
(2)创建BFC的元素,它的边框盒不会与浮动元素重叠
我们写了如下代码,到浏览器上看效果
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
<style>
.float{
width: 200px;
height: 200px;
margin: 10px;
background: rgb(197, 10, 10);
float: left;
}
.container{
height: 00px;
background: rgb(7, 220, 248);
}
</style>
</head>
<body>
<div class="float"></div>
<div class="container"></div>
</body>
</html>
常规流完全无视浮动元素,效果如下:
一旦让container创建BFC,事情就变得不一样了。我们修改如下代码:
.container{
height: 300px;
background: rgb(7, 220, 248);
overflow: hidden;
}
再回到页面上看,container避开了float元素:
这个时候我们修改container的margin-left属性,试图调整和左边固定宽度的红色矩形距离,发现不起作用,因为它参照的是窗口左边缘,而不是红色矩形。也就是当调整到数值大于本身到页面左边缘距离的时候,才开始有作用,如下所示:
这就说明了BFC会避开浮动元素,这样的特性对于我们制作两栏布局有很大帮助,尤其是一栏固定宽,另一栏自适应。
(3)创建BFC的元素,它的边框盒不会与浮动元素重叠
以下代码到页面上看,你会发现,两者上边框重合。
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
<style>
.container{
height: 300px;
margin-top: 80px;
background: rgb(212, 74, 208);
}
.child{
height: 100px;
margin: 50px;
background: rgb(20, 228, 100);
}
</style>
</head>
<body>
<div class="container">
<div class="child"></div>
</div>
</body>
</html>
无论你怎么调margin值,上边框都死死重合。
这个时候就要运用BFC来解决,我们对代码做出如下修改,让父元素创建BFC:
.container{
height: 300px;
margin-top: 80px;
background: rgb(212, 74, 208);
overflow: hidden;
}
再回到页面上看,两者上边框不重合:
子元素是container产生的BFC,而container是根元素产生的BFC,所以他们不是同一个上下文产生的BFC,这就是说上边框不重合的原因。
3、总结
BFC就是产生一个独立的渲染区域,不同上下文产生的BFC之间互不干扰。比如绝对定位会脱离常规文档流进行定位,其父元素不会自动计算它的高度,会选择忽视。这对于解决CSS的经典布局bug,或者是平时项目的布局都有很大帮助。
下一篇博客,我会介绍利用BFC还有其他的布局技巧来进行页面布局,比如三栏布局、两栏布局等等,敬请期待。