在学习 CSS 中,经常会听到 BFC 这个词,特别是在浮动布局或者是在外边距处理的时候,那么什么是 BFC 呢?BFC 到底有什么作用呢?
什么是 BFC?#
我们来看一看MDN中对 BFC 概念的解释。
块格式化上下文(Block Formatting Context,BFC) 是 Web 页面的可视化 CSS 渲染的一部分,是布局过程中生成块级盒子的区域,也是浮动元素与其他元素的交互限定区域。
从概念中可以看出,BFC 是生成块级盒子的区域,并且在与浮动元素的交互有特殊作用。那怎么样才能创造 BFC 区域呢?创造 BFC 的方法非常多,下面只列举常见的方法。
- 根元素或包含根元素的元素
- 浮动元素(元素的 float 不是 none)
- 绝对定位元素(元素的 position 为 absolute 或 fixed)
- 行内块元素(元素的 display 为 inline-block)
- 表格单元格(元素的 display 为 table-cell,HTML 表格单元格默认为该值)
- overflow 值不为 visible 的块元素
- display 值为 flow-root 的元素
- 弹性元素(display 为 flex 或 inline-flex 元素的直接子元素)
- 网格元素(display 为 grid 或 inline-grid 元素的直接子元素)
BFC 的特性#
同样看看 MDN 的解释吧:
“创建了 BFC 的元素中的所有的内容都会被包含到该 BFC 中。块格式化上下文对浮动定位(参见 float)与清除浮动(参见 clear)都很重要。浮动定位和清除浮动时只会应用于同一个 BFC 内的元素。浮动不会影响其它 BFC 中元素的布局,而清除浮动只能清除同一 BFC 中在它前面的元素的浮动。外边距折叠(Margin collapsing)也只会发生在属于同一 BFC 的块级元素之间。”。
通过上面的特性,我们了解到了以下信息:
- BFC 会把它里面的子元素都包含起来,其中包括脱离了文档流的浮动元素
- BFC 对于浮动有非常重要的应用
- BFC 对于外边距折叠也有影响
下面,我们会通过几个案例来加深对上面特性的理解。
BFC 的应用#
清除文字环绕#
<style>
section {
border: 1px solid blue;
margin: 0 0 10px;
}
img {
float: left;
}
p {
margin: 0;
}
</style>
<section>
<img src="./images/iwatch.png" />
<p>
Apple Watch 是苹果公司于2014年9月10日公布的一款智能手表,有Apple
Watch、Apple Watch Sport 和Apple Watch Edition 三种风格不同的系列。Apple
Watch 采用人造蓝宝石水晶屏幕与Force Touch触摸技术,有多种颜色可供选择。Apple
Watch Sport 共10款:起价为2588元,最高2988元。Apple Watch
共20款,起价为4188元,最高8288元。Apple Watch Edition
共8款,起价为74800元,最高126800元。三个系列都于2015年4月10日接受预定,4月24日起正式发售。首发地区包括中国大陆、中国香港、美国、日本、英国、法国、加拿大、澳大利亚。Apple
Watch 于2015年4月10日开放试戴预约。
</p>
</section>
这是最基本的文字环绕图片,图文混排的效果,其实浮动设计的最初目的就是为了图文混排效果的。但是如果我们要使得文字不要环绕图片,要怎么做呢? 只需要使得p元素成为 BFC 就可以了,这样p元素就是一个独立的 BFC。这样就不会被外面的其他的元素所影响。怎么使得p元素成为 BFC 呢?这里选用最新的方法,添加显示display:flow-root,这个是display最新的属性,用来创建 BFC 的。
<style>
section {
border: 1px solid blue;
margin: 0 0 10px;
}
img {
float: left;
}
p {
margin: 0;
display: flow-root;
}
</style>
<section>
<img src="./images/iwatch.png" />
<p>
Apple Watch 是苹果公司于2014年9月10日公布的一款智能手表,有Apple
Watch、Apple Watch Sport 和Apple Watch Edition 三种风格不同的系列。Apple
Watch 采用人造蓝宝石水晶屏幕与Force Touch触摸技术,有多种颜色可供选择。Apple
Watch Sport 共10款:起价为2588元,最高2988元。Apple Watch
共20款,起价为4188元,最高8288元。Apple Watch Edition
共8款,起价为74800元,最高126800元。三个系列都于2015年4月10日接受预定,4月24日起正式发售。首发地区包括中国大陆、中国香港、美国、日本、英国、法国、加拿大、澳大利亚。Apple
Watch 于2015年4月10日开放试戴预约。
</p>
</section>
这样,文字就不会环绕图片了。当然,你也可以设置p元素也浮动起来float:left,这样p元素也是成为了 BFC,但是这个 BFC 和上面形成的 BFC 有些差异,不会主动占满右边的剩余空间。如果想要达到两栏都浮动的效果的话,需要设置适当宽度才行(本身宽度加上图片宽度需要小于窗口的宽度),应为p是块级元素,默认是占满整行的,但是左边被图片占据了部分空间,就不能浮上来了。其实这也就是两栏布局或者多栏浮动布局的原理。
清除浮动#
浮动使得元素脱离文档流,但是没有脱离文本流,紧跟其后的元素也会在空间允许的情况下向上和向左(默认向左)浮动(填充)。这样就会打乱原先的布局,使得页面混乱。
<style>
section {
border: 1px solid blue;
margin: 0 0 10px;
}
img {
float: left;
}
p {
margin: 0;
}
footer {
border: 1px solid red;
}
</style>
<section>
<img src="./images/iwatch.png" />
<p>It's fun to float.</p>
</section>
<footer>
Here is the footer element that runs across the bottom of the page.
</footer>
上面的代码中图片增加了浮动属性float:left,使得图片向左浮动起来,但是后面的footer元素竟然也跟着浮动起来了,紧跟在p元素后面,这就不是我们想要的结果了。(浮动使得元素脱离了文档流(浮动起来),但是没有脱离文本流,所以会占据一定的空间位置,浮动后面的元素如果在有空间的前提下,会一起挤上来填满空间,所以如果计算 BFC 的高度的话,需要把浮动元素的高度也要计算在内。只有绝对定位和固定定位的元素是完全脱离文档流和文本流的,所以会和其他的元素重叠在一起。)
这个时候就需要清除浮动了,使用 BFC 的特性很容易清除浮动。因为 BFC 会把浮动的子元素也包裹起来,并且和外届隔离开来。给父元素section元素添加display:flow-root属性使它成为 BFC,和外届隔离开来,即外面的元素不会受到 BFC 里面浮动元素的影响,即清除了 BFC 里面元素浮动的影响。
<style>
section {
border: 1px solid blue;
margin: 0 0 10px;
display: flow-root;
}
img {
float: left;
}
p {
margin: 0;
}
footer {
border: 1px solid red;
}
</style>
<section>
<img src="./images/iwatch.png" />
<p>It's fun to float.</p>
</section>
<footer>
Here is the footer element that runs across the bottom of the page.
</footer>
清除外边距折叠#
<style>
* {
margin: 0;
padding: 0;
}
section {
background: red;
margin-top: 20px;
height: 100%;
}
p {
height: 100px;
margin: 20px 0;
background: yellow;
}
</style>
<section>
<p>1</p>
<p>2</p>
<p>3</p>
</section>
在代码中我们不仅设置了p元素的上下的外边距为 20px,而且还设置了它的父元素section元素上外边距也为 20px。虽然设置了多处外边距,但是貌似没有达到我们想要的效果。从图片中可以看到,一些元素的外边距被折叠了,主要有两处:
- 第一处是父子元素元素之间的折叠:
section元素到根元素的上外边距和第一个p元素到section的外边距折叠了,显示的外边距是section元素到根元素的上外边距,也就是最上面白色部分的(因为没有设置根元素的背景色,所以默认是白色),高度只有 20px。 - 第二处是兄弟元素之间的折叠:各个
p元素之间的外边距折叠了,外边距没有想加(20+20=40px),而是只有 20px。
在一开始就学 CSS 的时候我就知道,如果两个相邻边界都有外边距,外边距会折叠,只取最大的外边距。学习了 BFC 后才知道,外边距折叠也只会发生在属于同一 BFC 的块级元素之间,如果在不同的 BFC 的里,就不会折叠了,因为每个 BFC 都形成独立的区域。下面解决这两处外部去折叠的问题:
- 给
section元素添加属性display:flow-root,使它成为一个新的独立的 BFC,区别于以前所在的 BFC(由根元素形成的 BFC),之后这个 BFC 里面第一个p元素到section元素的上外边距就会显示出来了,为下图白色部分下面的红色部分。 - 给第二个
p元素外包一层div,为这个div设置属性,使它成为一个新的 BFC,区别于以前所在的 BFC(由section元素形成的 BFC),为了便于区分,增加一个蓝色的边框样式。设置之后,第二个p元素和前后的两个p元素之间的外边距就不会折叠了,它的外边距就会显示出来了,如下图所示。
<style>
* {
margin: 0;
padding: 0;
}
section {
background: red;
margin-top: 20px;
height: 100%;
display: flow-root;
}
p {
height: 100px;
margin: 20px 0;
background: yellow;
}
.newBFC {
display: flow-root;
border: 1px solid blue;
}
</style>
<section>
<p>1</p>
<div class="newBFC"><p>2</p></div>
<p>3</p>
</section>
总结#
通过上面几个 BFC 实例的应用,我们知道了在页面上,每个 BFC 其实就是一个独立的容器(空间),容器里面的子元素不会影响到外面的元素,反之,外面的元素也不会影响到容器里面的元素。