HTML+CSS宝典 CSS进阶 块级格式上下文(BFC)
块级格式上下文(BFC)学习之后,将从更高的角度来看待常规流盒子的渲染,
而且这节课非常重要,会影响到我们做项目的时候,对整个网站的布局,布局的时候可能会用到 BFC 的知识。
BFC 也是在面试题中比较容易出现的知识,如果以后在面试的时候,或者与同事聊天的时候,
说把这个区域做一个 BFC,要知道意思是块级格式化上下文,我们简称 BFC。
一、什么是BFC
块级格式上下文全称 Block Formatting Context,简称 BFC
BFC是什么意思呢?
它是一块独立的渲染区域,它规规定了在该区域中,常规流块盒的布局。
我们这节课实际就是认识这句话到底是什么意思,把这句话认识清楚了,这节课就学习完了。
1、先看这句话后面这一部分:它规规定了在该区域中,常规流块盒的布局
这句的意思是,不是常规流的浮动、定位就不讨论了,这节课讨论的仅仅是常规流块盒的布局
回忆一下,常规流块盒的布局有哪些规则?
1. 常规流块盒在水平方向上,必须撑满包含块,
常规流块盒的总宽度(内容 + 边框 + padding + margin)必须要刚好等于包含块的宽度
2. 常规流块盒在包含块的垂直方向上依次摆放,
因为横向撑满了,没有空隙了,所以依次摆放
3. 常规流块盒若外边距(margin)无缝相邻,则进行外边距合并,
只要中间没有隔 border、padding(padding指嵌套结构)之类的东西,外边距相邻就会合并
4. 常规流块盒的自动高度 和 摆放位置,无视浮动元素,
就是无论盒子摆在哪里,还有高度自动的时候,都会无视浮动元素,当然更加无视定位元素,绝对定位、固定定位这些
上面这四点常规流块盒的布局,为什么要重新复习呢?
因为这些是块级格式化上下文所规定的,之前学习的时候说的是 视觉格式化模型 规定的,
应该这样说 视觉格式化模型 它里面包含了块级格式化上下文,而块级格式化上下文里面包含了这些具体的规则。
块级格式化上下文的范畴,它规定了在某一个区域中,常规流块盒的布局。
2、看这句话的前半部分,是这节课要讲的新知识,它是一块独立的渲染区域
就是说上面回顾的常规流块盒的布局,它是在某一个区域里面,这个区域就是块级格式化上下文,就是BFC创建的区域。
在这个区域里面常规流块盒是这样来排列的,
垂直排列、横向撑满、外边距合并、以及不计算浮动元素,这些规则都在一个区域中有效的,这个区域就叫做块级格式化上下文。
首先它是一个独立渲染区域,在这个区域里才会产生这些规则,这个渲染区域是怎么产生的呢?
二、如何创建BFC区域
BFC渲染区域由某个HTML元素创建,以下元素会在其内部创建BFC区域
1. 根元素,根元素就是HTMl元素,就意味着<html>元素创建的BFC区域,覆盖了网页中所有的元素
2. 浮动和绝对定位元素,在它的内部也会创建BFC区域
3. overflow属性不等于visible的块盒(overflow默认值是visible),overflow的值只要不是visible,这样的一个块盒也会在内部创建一个BFC区域
4. 还有display属性等于table,或者是表格的单元格,什么行块盒,这些也会在内部创建BFC,只不过上面三个是比较常见的
看下面这张图里面的元素形成了父子关系,A元素包含B元素、C元素包含D元素…
分析一下,这些元素处于谁创建的BFC区域?
首先是根元素(根元素是HTML)会创建一个BFC( 淡绿色表示整个覆盖的区域 ),根元素覆盖了网页中所有的区域
根元素会创建BFC,其它元素也会创建
A元素 是浮动元素也会创建BFC
C元素 是绝对定位的元素也会创建BFC(包括固定定位fixed)
G元素 overflow: hidden 也会创建BFC
因此页面上除了HTML元素,还有三个元素也创建了BFC
接下来思考一下,元素B处于谁创建的BFC区域里面?
元素B处在的区域,是由元素A创建的BFC所覆盖
所以总结起来
元素A、元素C、元素E、元素F、元素G,这些元素的他们所在区域,都处于根元素创建的BFC区域
元素B 所处位置,是元素A创建的BFC
元素D 所处位置,是元素C创建的BFC
元素H 所处位置,是元素G创建的BFC
也就是说这些元素,可能会处于不同的块级格式上下文里面。
我们上面学习了什么是渲染区域,它是怎么创建的,
下面学习什么是独立的渲染区域,独立就是分割开,里面的不影响外面的
三、BFC是独立的渲染区域
不同的BFC区域,它们进行渲染时互不干扰,创建BFC的元素,隔绝了它内部和外部的联系,内部的渲染不会影响到外部
具体来说有三个具体的规则
1. 创建BFC的元素,它的自动高度需要计算浮动元素
2. 创建BFC的元素,它的边框盒不会与浮动元素重叠
3. 创建BFC的元素,不会和它的子元素进行外边距合并
1、创建BFC的元素,它的自动高度需要计算浮动元素
常规流元素自动高度不会计算浮动元素,常规流看不见浮动的盒子,所以高度坍塌了,以前是给父元素加 .clearfix 样式清除浮动
.clearfix::after{ content: ""; display: block; clear: both; }
现在学了BFC后还有一种做法,
创建BFC的元素,它的自动高度需要计算浮动元素,也就只要让父亲元素.container创建BFC就行了,就是创建了BFC盒子的高度要计算里面的浮动元素
这两种方法都会创建BFC,
position: absolute; 绝对定位的元素内部要创建BFC,
float: left; 浮动元素内部也会创建BFC,
但是这两种方式都不太好,因为会改变盒子的排列方式,本来是常规流,把布局方式变了,会影响到布局
所以往往使用副作用最小的方式 overflow: hidden; ,overflow的值只要不是visible(可以改成scroll,也可以改成auto)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>创建BFC的元素,它的自动高度需要计算浮动元素</title> <style> .container{ background-color: lightblue; width: 600px; /* position: absolute; 绝对定位创建BFC */ /* float: left; 浮动创建BFC */ overflow: hidden; /* 可以改成scroll,也可以改成auto */ } .item{ float: left; width: 100px; height: 100px; margin: 10px; background-color: #008c8c; } </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>
overflow:scroll 或 overflow:auto 还是会有副作用,可能会出现滚动条,副作用最小的方式是溢出隐藏 overflow:hidden
有些网站为了解决高度坍塌,可能没有使用清除法浮动的方式,使用了 overflow: hidden; 的方式
.clearfix{ overflow: hidden; }
不过如果仅仅是解决高度坍塌,清除浮动的方式是副作用是最小的,建议使用清楚浮动,因为有些元素就是要不在包含块内的。
2、创建BFC的元素,它的边框盒不会与浮动元素重叠
下面代码中两个元素应该怎样排列?
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style> .float{ width:100px; height:100px; margin:10px; background-color: red; float: left; } .container{ height: 200px; background-color: #008c8c; } </style> </head> <body> <div class="float"></div> <div class="container"></div> </body> </html>
常规流元素摆放的时候,看不到浮动元素,它只看得到常规流,所以完全无视浮动元素在哪!
但是一旦让.container 元素内部创建BFC,
设置 overflow: hidden 创建了BFC之后,因为BFC里面的区域是一块独立渲染区域,一定不跟其它其它元素相互干扰
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>创建BFC的元素,它的边框盒不会与浮动元素重叠</title> <style> .float{ width:100px; height:100px; margin:10px; background-color: red; float: left; } .container{ height: 200px; background-color: #008c8c; overflow: hidden; /* 创建BFC */ } </style> </head> <body> <div class="float"></div> <div class="container"></div> </body> </html>
所以这个时候.container元素排列的时候,一定会避开浮动元素
实际上浏览器给.container元素设置了一个margin-left,避开了浮动元素,
所以现在给.container元素设置margin-left没有效果
如果要设置这两个元素的距离,要设置.float浮动盒子的 margin-right 属性
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>创建BFC的元素,它的边框盒不会与浮动元素重叠</title> <style> .float{ width:100px; height:100px; margin:10px; background-color: red; float: left; margin-right:100px; /* 设置浮动盒子margin-right */ } .container{ height: 200px; background-color: #008c8c; overflow: hidden; /* 创建BFC */ } </style> </head> <body> <div class="float"></div> <div class="container"></div> </body> </html>
margin属性也是盒子的一部分,为了避开浮动元素,蓝色的盒子位置只能向右边移动了
这个现象对我们布局帮助很大,有时候我们可以把左边栏的宽度固定,然后另外一部分自动适应
3、 创建BFC的元素,不会和它的子元素进行外边距合并
实际上还可以换一个说法:
处在不同BFC中的元素,他们的外边距是不可能合并的,只有在同一个BFC里面的元素,外边距才能合并。
看例子
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style> .container{ height: 100px; background-color: #008c8c; margin-top:30px; } .child{ height:50px; margin:30px; background-color: red; } </style> </head> <body> <div class="container"> <div class="child"></div> </div> </body> </html>
.child元素的上外边距 和 .container元素的上外边距合并了
但是给外面的.container元素加上 overflow: hidden,上外边距就不合并了
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style> .container{ height:100px; background-color:#008c8c; margin-top:30px; overflow:hidden; /* 创建BFC */ } .child{ height:50px; margin:30px; background-color: red; } </style> </head> <body> <div class="container"> <div class="child"></div> </div> </body> </html>
1. .container 元素处于根元素 HTML 创建的 BFC 里面,
2. 而 .child 元素处于,.container 元素创建的 BFC 里面,
3. 他们的外边距尽管相邻,但是由于这两个元素,不是处于同一个 BFC,它们之间的渲染是不互相干扰的,因此他们的外边距是不能合并的
4、创建BFC的元素,它的边框盒不会与浮动元素重叠
这句话,边框盒不会与浮动元素重叠,只是浮动元素了,
绝对定位的元素和固定定位的元素就不考虑,绝对定位的元素 和 固定定位的元素是完全脱离常规流的,
浮动还和常规流之间还有一定联系,比如行盒排列的时候要避开浮动
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>不会与浮动元素重叠</title> <style> .container{ overflow: hidden; background-color: #008c8c; } .item{ float: left; margin: 20px; width: 200px; height: 200px; background-color: red; } </style> </head> <body> <div class="container"> <div class="item"></div> </div> </body> </html>
因为父级元素是BFC,所以计算浮动元素的高度
如果子元素不是浮动元素,是绝对定位元素,就脱离常规流了,父级元素就坍塌了
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style> .container{ overflow: hidden; background-color: #008c8c; } .item{ /* float: left; */ position: absolute; margin: 20px; width: 200px; height: 200px; background-color: red; } </style> </head> <body> <div class="container"> <div class="item"></div> </div> </body> </html>
总结,
绝对定位元素和固定定位元素,不可能计算它的高度,完全无视,因为它彻底脱离了常规流
display: flow-root