BFC(Block Formatting Context) 是Web页面中盒模型布局的CSS渲染模式。它的定位体系 属于 常规文档流 。摘自 W3C :javascript
浮动,绝对定位元素, inline-blocks
, table-cells
, table-captions
,和overflow
的值不为 visible
的元素,(除了这个值已经被传到了视口的时候)将建立一个新的 块级格式化上下文
。css
上面的引述几乎总结了一个 BFC 是怎样造成的。可是让咱们以另外一种方式来从新定义以便能更好的去理解。一个BFC是一个 HTML
盒子而且至少知足下列条件中的任何一个:html
float
的值不为 none
position
的值不为 static
或者 relative
display
的值为 table-cell
, table-caption
, inline-block
, flex
, 或者 inline-flex
中的其中一个overflow
的值不为 visible
一个BFC能够被显式的触发。若是想要建立一个新的BFC,只须要给它添加上面提到的任何一个CSS样式就能够了。java
例如,请看下面的 HTML
:web
<div class="container">
Some Content here
</div>
一个新的BFC能够经过给容器添加任何一个触发BFC的CSS样式,如 overflow: scroll
, overflow: hidden
, display: flex
, float: left
,或者 display: table
来建立。浏览器
display:table
可能会产生一些问题overflow:scroll
可能会显示没必要要的滚动条float:left
将会把元素置于容器的左边,其余元素环绕着它overflow:hidden
将会剪切掉溢出的元素因此每当想要建立一个新的BFC的时候,咱们会基于咱们的需求选择最好的样式条件。为了一致性,我在这篇文章所给出的例子中所有使用了 overflow: hidden
less
container {
overflow: hidden;
}
你能够自由使用除了 overflow: hidden
以外的样式声明。ide
W3C规范这样描述:布局
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).flex
在BFC中,每一个盒子的左外边框紧挨着包含块的左边框(从右到左的格式,则为紧挨右边框)。即便存在浮动也是这样的(尽管一个盒子的边框会因为浮动而收缩),除非这个盒子的内部建立了一个新的BFC浮动,盒子自己将会变得更窄)。
简单来讲,在上图中咱们能够看到,全部属于同一个BFC的盒子都左对齐(左至右的格式),他们的左外边框紧贴着包含块的左边框。在最后一个盒子里咱们能够看到尽管那里有一个浮动元素(棕色)在它的左边,另外一个元素(绿色)仍然紧贴着包含块的左边框。关于为何会发生这种状况的原理将会在下面的文字环绕部分进行讨论。
在常规文档流中,盒子都是从包含块的顶部开始一个接着一个垂直堆放。两个兄弟盒子之间的垂直距离是由他们个体的外边距所决定的,但不是他们的两个外边距之和。
为了去理解它,让咱们来思考一下下面这个例子。
在上图中咱们看到在红色盒子(一个 div
)中包含两个绿色的兄弟元素( p
元素),一个BFC已经被建立。
<div class="container"> <p>Sibling 1</p> <p>Sibling 2</p> </div>
相应的CSS:
.container { background-color: red; overflow: hidden; /* creates a block formatting context */ } p { background-color: lightgreen; margin: 10px 0; }
理论上两个兄弟元素之间的边距应该是来两个元素的边距之和( 20px
),但它实际上为 10px
。这就是被称为 外边距折叠 。当兄弟元素的外边距不同时,将以最大的那个外边距为准。
这一开始听起来可能有些困惑,由于咱们在前面讨论了BFC致使外边距折叠的问题。但咱们必须牢记在心的是毗邻块盒子的垂直外边距折叠只有他们是在同一BFC时才会发生。若是他们属于不一样的BFC,他们之间的外边距将不会折叠。因此经过建立一个新的BFC咱们能够防止外边距折叠。
让咱们在前面的例子中添加第三个兄弟元素,它的HTML将变为:
<div class="container"> <p>Sibling 1</p> <p>Sibling 2</p> <p>Sibling 3</p> </div>
相应的CSS变为:
.container { background-color: red; overflow: hidden; /* creates a block formatting context */ } p { background-color: lightgreen; margin: 10px 0; }
结果将会和上面的同样。即,这将会有一个折叠,三个兄弟元素将会以垂直距离为10px
的距离分开。会这样是由于三个 p
标签都是属于同一个BFC。
如今让咱们来修改第三个兄弟元素使得它属于另外一个新的BFC。它的HTML将变为:
<div class="container"> <p>Sibling 1</p> <p>Sibling 2</p> <div class="newBFC"> <p>Sibling 3</p> </div> </div>
CSS变为:
.container { background-color: red; overflow: hidden; /* creates a block formatting context */ } p { margin: 10px 0; background-color: lightgreen; } .newBFC { overflow: hidden; /* creates new block formatting context */ }
如今,在输出效果上将会有不一样的地方:
当第二和第三个兄弟元素属于不一样的BFC时,在他们之间将不会有任何外边距折叠,在下面的DEMO中能很明显看到。
一个BFC能够包含浮动。不少时候咱们会碰到这种状况,一个容器里有浮动元素。因为这个缘由,容器元素没有高度,它的浮动孩子将会脱离页面的常规流。咱们一般使用清除浮动来解决这个问题,最受欢迎的方法是使用一个 clearfix
的伪类元素。但咱们一样能够经过定义一个BFC来达到这个目的。
让咱们来看看一个例子:
<div class="container"> <div>Sibling</div> <div>Sibling</div> </div>
它的CSS:
.container { background-color: green; } .container div { float: left; background-color: lightgreen; margin: 10px; }
在上面的这个案例中,父容器将不会有任何的高度,它将不会包含已经浮动的子元素。为了解决这个问题,咱们经过添加 overflow: hidden
,在容器中建立一个新的BFC。通过修改过的 CSS
为:
.container { overflow: hidden; /* creates block formatting context */ background-color: green; } .container div { float: left; background-color: lightgreen; margin: 10px; }
如今,这个容器将包含浮动的子元素,它的高度将扩展到能够包含它的子元素,在这个BFC,这些元素将会回到页面的常规文档流。
有时候一个浮动 div
周围的文字环绕着它(以下图中的左图所示)可是在某些案例中这并非可取的,咱们想要的是外观跟下图中的右图同样的。为了解决这个问题,咱们可能使用外边距,可是咱们也可使用一个BFC来解决。
首先让咱们理解文字为何会环绕。为此咱们须要知道当一个元素浮动时盒子模型是如何工做的。这就是我以前在讨论BFC对齐时留下的那部分。让咱们从下图来了解发生了什么。
图中的HTML能够假定为这样:
<div class="container"> <div class="floated">Floated div</div> <p>Quae hic ut ab perferendis sit quod architecto,dolor debitis quam rem provident aspernatur tempora expedita.</p> </div>
在上图中的整个黑色区域为 p
元素。正如咱们所看到的,这个 p
元素并无移动,可是它却出如今浮动元素的下方。 p
元素的 line boxes
(指的是文本行)进行了移位。此处 line boxes
的水平收缩为浮动元素提供了空间。
随着文字的增长,由于 line boxes
再也不须要移位,最终将会环绕在浮动元素的下方,所以出现了那样的状况。这就解释了为何即便在浮动元素存在时,段落也将紧贴在包含块的左边框上,还有为何 line boxes
会缩小以容纳浮动元素。
若是咱们可以移动整个 p
元素,那么这个环绕的问题就能够解决了。
在去解决以前,让咱们再回忆一下 W3C
标准上是怎么描述的:
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).
在BFC中,每一个盒子的左外边框紧挨着左边框的包含块(从右到左的格式化时,则为右边框紧挨)。即便在浮动里也是这样的(尽管一个盒子的边框会由于浮动而萎缩),除非这个盒子的内部建立了一个新的BFC(这种状况下,因为浮动,盒子自己将会变得更窄),
根据这些,若是这个 p
元素建立了一个新的BFC,那么它将不会紧挨着容器块的左边缘。这个能够经过简单的给 p
元素添加 overflow: hidden
来实现。这个方法建立了一个新的BFC解决了文字环绕在浮动元素周围的问题。
若是咱们正在建立的一个多列布局占满了整个容器的宽度,在某些浏览器中最后一列有时候将会被挤到下一行。会发生这样多是由于浏览器舍入(取整)了列的宽度使得总和的宽度超过了容器的宽度。然而,若是咱们在一个列的布局中创建了一个新的BFC,它将会在前一列填充完以后的后面占据所剩余的空间。
让咱们使用多列布局中的三列布局来做为例子。
这是HTML代码:
<div class="container"> <div class="column">column 1</div> <div class="column">column 2</div> <div class="column">column 3</div> </div>
这是CSS代码:
.column { width: 31.33%; background-color: green; float: left; margin: 0 1%; } .column:last-child { float: none; overflow: hidden; }
在CodePen 上DEMO的运行结果:
如今即便容器的宽度会有轻微的变化,可是布局也不会中断。固然,这并非多列布局的最好选择,但它是防止最后一列下滑问题的一种方法。Flexbox在这种状况下多是一个更好的解决方案,可是这应该要说明一下在这些状况下元素是如何表现的。
我但愿这篇文章已经向你展现了BFC的相关特性,以及他们如何影响元素在页面上的视觉定位。全部的例子都展现了它们在实际案例中的应用,这应该会使得他们更加清晰。
若是你有任何东西想要补充,请在评论中让咱们知道。若是你想要更深刻的讨论的话,请务必在W3C上的 讨论话题 中留言。
本文根据 @Ritesh Kumar 的《 Understanding Block Formatting Contexts in CSS 》所译,整个译文带有咱们本身的理解与思想,若是译得很差或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://www.sitepoint.com/understanding-block-formatting-contexts-in-css/ 。