在一个Web页面的CSS渲染中,块级格式化上下文 (Block Fromatting Context)是按照块级盒子布局的。W3C对BFC的定义以下:html
浮动元素和绝对定位元素,非块级盒子的块级容器(例如 inline-blocks, table-cells, 和 table-captions),以及overflow值不为“visiable”的块级盒子,都会为他们的内容建立新的BFC(块级格式上下文)。
为了便于理解,咱们换一种方式来从新定义BFC。一个HTML元素要建立BFC,则知足下列的任意一个或多个条件便可:git
一、float的值不是none。
二、position的值不是static或者relative。
三、display的值是inline-block、table-cell、flex、table-caption或者inline-flex
四、overflow的值不是visiblegithub
BFC是一个独立的布局环境,其中的元素布局是不受外界的影响,而且在一个BFC中,块盒与行盒(行盒由一行中全部的内联元素所组成)都会垂直的沿着其父元素的边框排列。segmentfault
要显示的建立一个BFC是很是简单的,只要知足上述4个CSS条件之一就行。例如:浏览器
<div class="container"> 你的内容 </div>
在类container中添加相似 overflow: scroll,overflow: hidden,display: flex,float: left,或 display: table 的规则来显示建立BFC。虽然添加上述的任意一条都能建立BFC,但会有一些反作用:app
一、display: table 可能引起响应性问题
二、overflow: scroll 可能产生多余的滚动条
三、float: left 将把元素移至左侧,并被其余元素环绕
四、overflow: hidden 将裁切溢出元素ide
于是不管何时须要建立BFC,都要基于自身的须要来考虑。对于本文,将采用 overflow: hidden 方式:布局
.container { overflow: hidden; }
如前文所说,在一个BFC中,块盒与行盒(行盒由一行中全部的内联元素所组成)都会垂直的沿着其父元素的边框排列。W3C给出得规范是:flex
在BFC中,每个盒子的左外边缘(margin-left)会触碰到容器的左边缘(border-left)(对于从右到左的格式来讲,则触碰到右边缘)。浮动也是如此(尽管盒子里的行盒子 Line Box 可能因为浮动而变窄),除非盒子建立了一个新的BFC(在这种状况下盒子自己可能因为浮动而变窄)。
常规流布局时,盒子都是垂直排列,二者之间的间距由各自的外边距所决定,但不是两者外边距之和。this
<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; }
在上图中,一个红盒子(div)包含着两个兄弟元素(p),一个BFC已经建立了出来。
理论上,两个p元素之间的外边距应当是两者外边距之和(20px)但实际上倒是10px,这是外边距折叠(Collapsing Margins)的结果。
在CSS当中,相邻的两个盒子(多是兄弟关系也多是祖先关系)的外边距能够结合成一个单独的外边距。这种合并外边距的方式被称为折叠,而且于是所结合成的外边距称为折叠外边距。折叠的结果按照以下规则计算:
一、两个相邻的外边距都是正数时,折叠结果是它们二者之间较大的值。
二、两个相邻的外边距都是负数时,折叠结果是二者绝对值的较大值。
三、两个外边距一正一负时,折叠结果是二者的相加的和。
产生折叠的必备条件:margin必须是邻接的! (对于不产生折叠的状况,见参考文章的连接)
BFC可能形成外边距折叠,也能够利用它来避免这种状况。BFC产生外边距折叠要知足一个条件:两个相邻元素要处于同一个BFC中。因此,若两个相邻元素在不一样的BFC中,就能避免外边距折叠。
改进前面的例子:
<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; }
结果和上面同样,因为外边距折叠,三个相邻P元素之间的垂直距离是10px,这是由于三个 p 标签都从属于同一个BFC。
修改第三个P元素,使之建立一个新的BFC:
<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 */ }
由于第二个和第三个P元素如今分属于不一样的BFC,它们之间就不会发生外边距折叠了。
浮动元素是会脱离文档流的(绝对定位元素会脱离文档流)。若是一个没有高度或者height是auto的容器的子元素是浮动元素,则该容器的高度是不会被撑开的。咱们一般会利用伪元素(:after或者:before)来解决这个问题。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; }
在上面这个例子中,容器没有任何高度,而且它包不住浮动子元素,容器的高度并不会被撑开。为解决这个问题,能够在容器中建立一个BFC:
.container { overflow: hidden; /* creates block formatting context */ background-color: green; } .container div { float: left; background-color: lightgreen; margin: 10px; }
如今容器能够包住浮动子元素,而且其高度会扩展至包住其子元素,在这个新的BFC中浮动元素又回归到页面的常规流之中了。
如上图所示,对于浮动元素,可能会形成文字环绕的状况(Figure1),但这并非咱们想要的布局(Figure2才是想要的)。要解决这个问题,咱们能够用外边距,但也能够用BFC。
First let us understand why the text wraps. For this we have to understand how the box model works when an element is floated. This is the part I left earlier while discussing the alignment in a block formatting context. Let us understand what is happening in Figure 1 in the diagram below:
假设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元素的文本(行盒子)却移位了,行盒子水平变窄来给浮动元素腾出了空间。随着文本的增长,最后文本将环绕在浮动元素之下,由于那时候行盒子再也不须要移位,也就成了图Figure1的样子。
再回顾一下W3C的描述:
在BFC上下文中,每一个盒子的左外侧紧贴包含块的左侧(从右到左的格式里,则为盒子右外侧紧贴包含块右侧),甚至有浮动也是如此(尽管盒子里的行盒子 Line Box 可能因为浮动而变窄),除非盒子建立了一个新的BFC(在这种状况下盒子自己可能因为浮动而变窄)。
于是,若是p元素建立一个新的BFC那它就不会再紧贴包含块的左侧了。
若是咱们建立一个占满整个容器宽度的多列布局,在某些浏览器中最后一列有时候会掉到下一行。这多是由于浏览器四舍五入了列宽从而全部列的总宽度会超出容器。但若是咱们在多列布局中的最后一列里建立一个新的BFC,它将老是占据其余列先占位完毕后剩下的空间。
例如:
<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%; } /* Establishing a new block formatting context in the last column */ .column:last-child { float: none; overflow: hidden; }
如今尽管盒子的宽度稍有改变,但布局不会打破。固然,对多列布局来讲这不必定是个好办法,但能避免最后一列下掉。这个问题上弹性盒或许是个更好的解决方案,但这个办法能够用来讲明元素在这些环境下的行为。