BFC全称是Block Formatting Context,即块格式化上下文。它是CSS2.1规范定义的,关于CSS渲染定位的一个概念。要明白BFC究竟是什么,首先来看看什么是视觉格式化模型。html
视觉格式化模型(visual formatting model)是用来处理文档并将它显示在视觉媒体上的机制,它也是CSS中的一个概念。浏览器
视觉格式化模型定义了盒(Box)的生成,盒主要包括了块盒、行内盒、匿名盒(没有名字不能被选择器选中的盒)以及一些实验性的盒(将来可能添加到规范中)。盒的类型由display
属性决定。bash
块盒有如下特性:less
display
为block
,list-item
或 table
时,它是块级元素 block-level;<li>
,生成额外的盒来放置项目符号,不过多数元素只生成一个主要块级盒。 display
的计算值为inline
,inline-block
或inline-table
时,称它为行内级元素;display:inline
的非替换元素生成的盒是行内盒;display
值为 inline-block
或 inline-table
的元素生成,不能拆分红多个盒;匿名盒也有份匿名块盒与匿名行内盒,由于匿名盒没有名字,不能利用选择器来选择它们,因此它们的全部属性都为inherit
或初始默认值;ide
以下面例子,会创键匿名块盒来包含毗邻的行内级盒:布局
<div>
Some inline text
<p>followed by a paragraph</p>
followed by more inline text.
</div>复制代码
在定位的时候,浏览器就会根据元素的盒类型和上下文对这些元素进行定位,能够说盒就是定位的基本单位。定位时,有三种定位方案,分别是常规流,浮动已经绝对定位。flex
position
为static
或relative
,而且float
为none
时会触发常规流;position: static
,盒的位置是常规流布局里的位置;position: relative
,盒偏移位置由这些属性定义top
,bottom
,left
andright
。即便有偏移,仍然保留原有的位置,其它常规流不能占用这个位置。top
,bottom
,left
及right
;position
为absolute
或fixed
,它是绝对定位元素;position: absolute
,元素定位将相对于最近的一个relative
、fixed
或absolute
的父元素,若是没有则相对于body
;到这里,已经对CSS的定位有必定的了解了,从上面的信息中也能够得知,块格式上下文是页面CSS 视觉渲染的一部分,用于决定块盒子的布局及浮动相互影响范围的一个区域。ui
float
不为none
);position
为absolute
或fixed
);inline-blocks
(元素的 display: inline-block
);display: table-cell
,HTML表格单元格默认属性);overflow
的值不为visible
的元素;display: flex
或inline-flex
);但其中,最多见的就是overflow:hidden
、float:left/right
、position:absolute
。也就是说,每次看到这些属性的时候,就表明了该元素以及建立了一个BFC了。atom
BFC的范围在MDN中是这样描述的。spa
A block formatting context contains everything inside of the element creating it that is not also inside a descendant element that creates a new block formatting context.
中文的意思一个BFC包含建立该上下文元素的全部子元素,但不包括建立了新BFC的子元素的内部元素。
这段看上去有点奇怪,我是这么理解的,加入有下面代码,class名为.BFC
表明建立了新的块格式化:
<div id='div_1' class='BFC'>
<div id='div_2'>
<div id='div_3'></div>
<div id='div_4'></div>
</div>
<div id='div_5' class='BFC'>
<div id='div_6'></div>
<div id='div_7'></div>
</div>
</div>复制代码
这段代码表示,#div_1
建立了一个块格式上下文,这个上下文包括了#div_2
、#div_3
、#div_4
、#div_5
。即#div_2
中的子元素也属于#div_1
所建立的BFC。但因为#div_5
建立了新的BFC,因此#div_6
和#div_7
就被排除在外层的BFC以外。
我认为,这从另外一方角度说明,一个元素不能同时存在于两个BFC中。
BFC的一个最重要的效果是,让处于BFC内部的元素与外部的元素相互隔离,使内外元素的定位不会相互影响。这是利用BFC清除浮动所利用的特性,关于清除浮动将在后面讲述。
若是一个元素可以同时处于两个BFC中,那么就意味着这个元素能与两个BFC中的元素发生做用,就违反了BFC的隔离做用,因此这个假设就不成立了。
就如刚才提到的,BFC的最显著的效果就是创建一个隔离的空间,断绝空间内外元素间相互的做用。然而,BFC还有更多的特性:
Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.
In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block. The vertical distance between two sibling boxes is determined by the 'margin' properties. Vertical margins between adjacent block-level boxes in a block formatting context collapse.
In a block formatting context, each box's left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch). This is true even in the presence of floats (although a box's line boxes may shrink due to the floats), unless the box establishes a new block formatting context (in which case the box itself may become narrower due to the floats).
简单概括一下:
这么多性质有点难以理解,但能够做以下推理来帮助理解:html的根元素就是<html>
,而根元素会建立一个BFC,建立一个新的BFC时就至关于在这个元素内部建立一个新的<html>
,子元素的定位就如同在一个新<html>
页面中那样,而这个新旧html页面之间时不会相互影响的。
上述这个理解并非最准确的理解,甚至是将因果倒置了(由于html是根元素,所以才会有BFC的特性,而不是BFC有html的特性),但这样的推理能够帮助理解BFC这个概念。
讲了这么多,仍是比较难理解,因此下面经过一些例子来加深对BFC的认识。
<style>
* {
margin: 0;
padding: 0;
}
.left{
background: #73DE80; /* 绿色 */
opacity: 0.5;
border: 3px solid #F31264;
width: 200px;
height: 200px;
float: left;
}
.right{ /* 粉色 */
background: #EF5BE2;
opacity: 0.5;
border: 3px solid #F31264;
width:400px;
min-height: 100px;
}
.box{
background:#888;
height: 100%;
margin-left: 50px;
}
</style>
<div class='box'>
<div class='left'> </div>
<div class='right'> </div>
</div>复制代码
显示效果:
绿色框('#left')向左浮动,它建立了一个新BFC,但暂时不讨论它所建立的BFC。因为绿色框浮动了,它脱离了本来normal flow的位置,所以,粉色框('#right')就被定位到灰色父元素的左上角(特性3:元素左边与容器左边相接触),与浮动绿色框发生了重叠。
同时,因为灰色框('#box')并无建立BFC,所以在计算高度的时候,并无考虑绿色框的区域(特性6:浮动区域不叠加到BFC区域上),发生了高度坍塌,这也是常见问题之一。
如今经过设置overflow:hidden
来建立BFC,再看看效果如何。
.BFC{
overflow: hidden;
}
<div class='box BFC'>
<div class='left'> </div>
<div class='right'> </div>
</div>复制代码
灰色框建立了一个新的BFC后,高度发生了变化,计算高度时它将绿色框区域也考虑进去了(特性5:计算BFC的高度时,浮动元素也参与计算);
而绿色框和红色框的显示效果仍然没有任何变化。
如今,现将一些小块添加到粉色框中,看看效果:
<style>
.little{
background: #fff;
width: 50px;
height: 50px;
margin: 10px;
float: left;
}
</style>
<div class='box BFC'>
<div class='left'> </div>
<div class='right'>
<div class='little'></div>
<div class='little'></div>
<div class='little'></div>
</div>
</div>复制代码
因为粉色框没有建立新的BFC,所以粉色框中白色块受到了绿色框的影响,被挤到了右边去了。先无论这个,看看白色块的margin。
利用同实例二中同样的方法,为粉色框建立BFC:
<div class='box BFC'>
<div class='left'> </div>
<div class='right BFC'>
<div class='little'></div>
<div class='little'></div>
<div class='little'></div>
</div>
</div>复制代码
一旦粉色框建立了新的BFC之后,粉色框就不与绿色浮动框发生重叠了,同时内部的白色块处于隔离的空间(特性4:BFC就是页面上的一个隔离的独立容器),白色块也不会受到绿色浮动框的挤压。
以上就是BFC的分析,BFC的概念比较抽象,但经过实例分析应该可以更好地理解BFC。在实际中,利用BFC能够闭合浮动(实例二),防止与浮动元素重叠(实例四)。同时,因为BFC的隔离做用,能够利用BFC包含一个元素,防止这个元素与BFC外的元素发生margin collapse。