什么是BFC

 

在一个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

要显示的建立一个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中盒子怎么对齐

如前文所说,在一个BFC中,块盒与行盒(行盒由一行中全部的内联元素所组成)都会垂直的沿着其父元素的边框排列。W3C给出得规范是:flex

在BFC中,每个盒子的左外边缘(margin-left)会触碰到容器的左边缘(border-left)(对于从右到左的格式来讲,则触碰到右边缘)。浮动也是如此(尽管盒子里的行盒子 Line Box 可能因为浮动而变窄),除非盒子建立了一个新的BFC(在这种状况下盒子自己可能因为浮动而变窄)。

img

外边距折叠

常规流布局时,盒子都是垂直排列,二者之间的间距由各自的外边距所决定,但不是两者外边距之和。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;
}

渲染结果如图:
img2

在上图中,一个红盒子(div)包含着两个兄弟元素(p),一个BFC已经建立了出来。

理论上,两个p元素之间的外边距应当是两者外边距之和(20px)但实际上倒是10px,这是外边距折叠(Collapsing Margins)的结果。

在CSS当中,相邻的两个盒子(多是兄弟关系也多是祖先关系)的外边距能够结合成一个单独的外边距。这种合并外边距的方式被称为折叠,而且于是所结合成的外边距称为折叠外边距。折叠的结果按照以下规则计算:

一、两个相邻的外边距都是正数时,折叠结果是它们二者之间较大的值。
二、两个相邻的外边距都是负数时,折叠结果是二者绝对值的较大值。
三、两个外边距一正一负时,折叠结果是二者的相加的和。

产生折叠的必备条件:margin必须是邻接的! (对于不产生折叠的状况,见参考文章的连接)

BFC能够作什么呢?

利用BFC避免外边距折叠

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 */
}

如今的结果如图:
img

由于第二个和第三个P元素如今分属于不一样的BFC,它们之间就不会发生外边距折叠了。

BFC包含浮动

浮动元素是会脱离文档流的(绝对定位元素会脱离文档流)。若是一个没有高度或者height是auto的容器的子元素是浮动元素,则该容器的高度是不会被撑开的。咱们一般会利用伪元素(:after或者:before)来解决这个问题。BFC能包含浮动,也能解决容器高度不会被撑开的问题。

img

看个例子:

<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中浮动元素又回归到页面的常规流之中了。

使用BFC避免文字环绕

img

如上图所示,对于浮动元素,可能会形成文字环绕的状况(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:

img

假设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

若是咱们建立一个占满整个容器宽度的多列布局,在某些浏览器中最后一列有时候会掉到下一行。这多是由于浏览器四舍五入了列宽从而全部列的总宽度会超出容器。但若是咱们在多列布局中的最后一列里建立一个新的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; 
}

如今尽管盒子的宽度稍有改变,但布局不会打破。固然,对多列布局来讲这不必定是个好办法,但能避免最后一列下掉。这个问题上弹性盒或许是个更好的解决方案,但这个办法能够用来讲明元素在这些环境下的行为。

相关文章
相关标签/搜索