当我们学习一样知识的时候,我们可以通过“3W+H”(what,when,why,how)的方法来检验自己对该知识点的掌握程度,如果你对上述的“3W”都能十分清楚的回答上来,说明你对该知识点的掌握还可以,如果不能,则说明你根本就没掌握
下面就BFC用“3W”的方法,谈一下自己对它的个人见解:
What:什么是BFC
MDN官方说法:
块格式化上下文(Block Formatting Context,BFC) 是Web页面的可视化CSS渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。
视觉格式化模型(visual formatting model)
是用来处理文档并将它显示在视觉媒体上的机制(说白了,这个模型就是控制生成不同的盒子),视觉格式化模型定义了盒(Box)的生成,盒主要包括了块盒、行内盒、匿名盒(没有名字不能被选择器选中的盒)以及一些实验性的盒(未来可能添加到规范中)。盒的类型由display
属性决定。
学过CSS的都知道,页面上的元素基本上都是一个个的盒子组成的(包括块盒、行内盒、匿名盒(没有名字不能被选择器选中的盒)),下面我们先来温习一下几个重要的盒子:
块盒(block box)
块盒有以下特性:
- 当元素的CSS属性
display
为block
,list-item
或table
时,它是块级元素 block-level; - 视觉上呈现为块,竖直排列;
- 块级盒参与(块格式化上下文);
- 每个块级元素至少生成一个块级盒,称为主要块级盒(principal block-level box)。一些元素,比如
<li>
,生成额外的盒来放置项目符号,不过多数元素只生成一个主要块级盒。
行内盒(inline box)
- 当元素的CSS属性
display
的计算值为inline
,inline-block
或inline-table
时,称它为行内级元素; - 视觉上它将内容与其它行内级元素排列为多行;典型的如段落内容,有文本(可以有多种格式譬如着重),或图片,都是行内级元素;
- 行内级元素生成行内级盒(inline-level boxes),参与行内格式化上下文(inline formatting context)。同时参与生成行内格式化上下文的行内级盒称为行内盒(inline boxes)。所有
display:inline
的非替换元素生成的盒是行内盒; - 不参与生成行内格式化上下文的行内级盒称为原子行内级盒(atomic inline-level boxes)。这些盒由可替换行内元素,或
display
值为inline-block
或inline-table
的元素生成,不能拆分成多个盒;
匿名盒(anonymous box)
匿名盒也有份匿名块盒与匿名行内盒,因为匿名盒没有名字,不能利用选择器来选择它们,所以它们的所有属性都为inherit
或初始默认值;
块盒和行内盒我们大家都比较熟悉了,下面举个简单的例子说明一下匿名盒:
<div class="container">
我是小妖怪,逍遥又自在
<h1>杀人不眨眼</h1>
吃人不放盐
</div>
container
就是一个默认的块元素,但是“我是小妖怪”也会生成一个盒子,由于我们无法用css选择器来选择它,所以这个盒子也就是匿名盒子。总而言之:BFC是决定块盒子的布局以及浮动相互影响的区域,归根揭底,BFC就是在CSS渲染的时候形成的一个块级区域,关于这个区域的特点,请见下文。
HOW:怎样形成一个BFC
- 根元素(html)或其它包含它的元素;
- 浮动 (元素的
float
不为none
); - 绝对定位元素 (元素的
position
为absolute
或fixed
); - 行内块
inline-blocks
(元素的display: inline-block
); - 表格单元格(元素的
display: table-cell
,HTML表格单元格默认属性); overflow
的值不为visible
的元素;- 弹性盒 flex boxes (元素的
display: flex
或inline-flex
);
也就是说,满足上面的任何一个条件,就会形成一个BFC,其中最常见的就是overflow:hidden
、float:left/right
、position:absolute。
BFC的范围
BFC包含创建该上下文元素的所有子元素,但不包括创建了新BFC的子元素的内部元素。
也就是说,一个BFC包含包含创建该上下文元素的所有子元素,但如果在一个BFC里面又生成了新的BFC,那么内部BFC的子元素将不受外部BFC的影响。也就是说对于一个具体的元素而言,其只能属于一个BFC,而不能同属于多个BFC。
BFC的特性:
下面就以上的几个特性用例子实际说明一下:
1. 内部的盒会在垂直方向一个接一个排列(可以看作BFC中有一个的常规流);
<style>
.bfc{
position: absolute; //使用了绝对定位,形成一个BFC
left: 100px;
top:100px;
width: 200px;
height: 200px;
border: 1px solid #ffcccc;
background:rgba(220, 14, 129, 0.5)
}
.item1,.item2{
border: 1px solid green;
padding: 10px;
margin: 20px
}
</style>
<div class="container bfc" >
<div class="item1">2</div>
<div class="item2">3</div>
</div>
其结果就是这样子:
可见在BFC内部形成正常的文档流,但却发生了方向上的margin重叠,要解决这个重叠,可以在内部重新生成一个新的BFC:
<div class="container bfc" >
<div class="item1">2</div>
<div class="bfc-inner">
<div class="item2">3</div>
</div>
</div>
<style>
.bfc{
position: absolute;
left: 100px;
top:100px;
width: 200px;
height: 200px;
border: 1px solid #ffcccc;
background:rgba(220, 14, 129, 0.5)
}
.item1,.item2{
border: 1px solid green;
padding: 10px;
margin: 20px;
}
.bfc-inner{
float: left ;// 新的bfc
}
.bfc-inner .item2{
width: 100%
}
</style>
margin的重叠不见了,因为item2已经不属于外部的BFC了
2. 计算BFC的高度时,考虑BFC所包含的所有元素,连浮动元素也参与计算(不会发生高度塌陷);
<style>
.bfc{
border: 1px solid #000;
}
.item1,.item2{
border: 1px solid green;
width: 100px;
height: 100px;
float: left
}
.item1{
background:blueviolet;
opacity: 0.4;
}
.item2{
background:brown;
opacity: 0.4;
}
</style>
<div class="bfc" >
<div class="item1">2</div>
<div class="item2">3</div>
</div>
会发生典型的高度塌陷:
但是当我们给.bfc
元素添加样式position:absolute
或者float:left
的时候,就会形成一个BFC,高度塌陷就消失了。
3. 浮动盒区域不叠加到BFC上(也就是说,浮动的元素不会遮挡住BFC);
还是使用上面的元素,不过样式变成了这个样子:
<style>
.bfc{
border: 1px solid #000;
}
.item1,.item2{
border: 1px solid green;
}
.item1{
background:blueviolet;
width: 100px;
height: 100px;
float: left
}
.item2{
width: 300px;
height: 100px;
background:brown;
}
</style>
这样的话,.item2
就会被.item1
遮挡
但是当我们给.item2
添加一个样式:overflow:hidden
的时候(形成了一个BFC),就不会被遮挡了。
WHEN和WHY
对于BFC,在我看来更像是一个策略,可以使用BFC的特性来解决不同的布局问题,比如高度塌陷,比如浮动遮挡的问题,垂直方向margin折叠等,其实我们会发现我们无意间就会使用BFC,理解并灵活使用BFC能让我们在布局的时候避免很多坑。
参考文章:
juejin.cn/post/684490…(网易考拉:学习BFC)