什么是BFC

一些元素,如float元素,如position为absolute,inline-block,table-cell或table-caption的元素,以及overflow属性不为visible的元素,它们将会建立一个新的块级格式化上下文(Block Formatting Context),也就是我们所说的BFC

怎么形成BFC

  • BFC也是HTML中的一个盒子(看不见而已),只有满足至少下列条件之一才能形成BFC:

    • float属性不为none.
    • position属性不为staticrelative.
    • display属性为下列之一:table-cell,table-caption,inline-block, flex,inline-flex.
    • overflow属性不为visible.
  • 我们可以用CSS为container容器附加上述条件,如overflow: scroll, overflow: hidden, display: flex, float: left, display: table.尽管这些条件都能形成一个BFC,但是它们各自却有着不一样的表现:

    • display: table : 在响应式布局中会有问题
    • overflow: scroll : 可能会出现你不想要的滚动条
    • float: left : 使元素左浮动,并且其他元素对其环绕
    • overflow: hidden : 消除溢出部分
  • 稍作比较就会发现,建立BFC最好的方法莫过于overflow:hidden了。

BFC的作用

  • BFC布局规则

    • 内部的Box会在垂直方向,一个接一个地放置。
    • Box***垂直方向***的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
    • 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
    • BFC的区域不会与float box重叠。
    • BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
    • 计算BFC的高度时,浮动元素也参与计算
  • 情景1: 利用BFC消除Margin Collapse

在正常情况下,在一个容器内的所有box将会由上至下依次垂直排列,即我们所说的一个元素占一行,并切垂直相邻的距离(即margin)是由各自的margin决定的,而不是两个margin的叠加。

让我们看一个例子:红色的div包含三个绿色的p元素

HTML代码:

<div class="container">
  <p>Sibling 1</p>
  <p>Sibling 2</p>
  <p>Sibling 3</p>
</div>

CSS代码:

.container {
  background-color: red;
  overflow: hidden;
}

p {
  background-color: lightgreen;
  margin: 10px 0;
}

理想情况下,我们会认为p标签之间的margin应该是它们的和(20px),但实际上却是10px.这其实是collapsing margins(外边距坍塌)。要注意的是,flex布局不存在collapsing margins,水平方向上也不存在collapsing margins

利用BFC能消除collapsing margins。紧记只有当元素在同一个BFC中时,垂直方向上的margin才会clollpase.如果它们属于不同的BFC,则不会有margin collapse.因此我们可以再建立一个BFC去阻止margin collpase的发生。还记得上文提到的形成BFC的方法和BFC内部规则吗?所以为了让他们的margins变成20,我们只需要用div,建立一个BFC,p元素处于不同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;
}
  • 情景2: 利用BFC容纳浮动元素

相信大家经常会遇到一个容器里有浮动元素,但是这个容器的高度却是0的场景,看以下例子:

Html代码:

<div id="div">
  <img src=".test.jpg">
</div>

Css代码:

#div {
  border: 5px solid red;
}

#div img {
  float: left;
}

比较为img的css加了float: left前后会发现,父元素高度会坍塌,border变成了一条线.通常我们解决这个问题的办法是利用一个伪元素去实现clear fix,代码如下:

HTML代码:

  <div id="div">
    <img src="./test.jpg">
    <div class="clearfix"></div>
  </div>

Css代码:

#div {
  border: 5px solid red;
}

#div img{
  float: left;
}

.clearfix {
  clear: both
}

此时父元素高度适应子元素,clear生效的原因, w3c中有这样一段描述clear的话:

在 CSS2.1 中,会在设置清除浮动的元素上,外边距之上增加清除空间,而外边距本身并不改变。”也就是说,因为浮动而产生的空白空间,会被填充为实际存在的空间。那么,自然就能撑开父元素。

但是现在我们有了更好的解决办法,即利用BFC,因为它够容纳浮动元素的(规则6)。代码如下:

HTML代码:

  <div id="div">
    <img src="./test.jpg">
  </div>

Css代码:

#div {
  border: 5px solid red;
  overflow: hidden;
}

#div img{
  float: left;
}

  • 情景3: 利用BFC阻止文本换行

有时候,确切的说大多数情况(若没有特殊设置),如Figure1,文本将会环绕浮动元素,但有时候这并不是我们期望的。我们期待的是Figure2如图:

关于float脱离文档流,而文字会环绕,这里有一段很好的回答,引用里面的话,总的来说,脱离文档流,也就是将元素从普通的布局排版中拿走,其他盒子在定位的时候,会当做脱离文档流的元素不存在而进行定位。需要注意的是,使用float脱离文档流时,其他盒子会无视这个元素,但其他盒子内的文本依然会为这个元素让出位置,环绕在周围。而对于使用position:absolute脱离文档流的元素,其他盒子与其他盒子内的文本都会无视它。

实际情况如例子:

Html代码:

  <div class="container">
    <div class="floated">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/man-jumping.jpg" alt="man jumping">
    </div>
    <p class="oh">Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quae hic ut ab perferendis sit quod architecto, dolor debitis quam rem provident aspernatur tempora expedita perspiciatis suscipit ipsam voluptas tenetur. Nostrum? Quae hic ut ab perferendis sit quod architecto. Quae hic ut ab perferendis sit quod architecto.</p>
  </div>

Css代码:

.container {
  width: 500px;
  min-height: 280px;
  border: 1px solid #aaa;
  padding: 10px;
}

.floated {
  float: left;
  margin: 5px;
}

p {
  margin: 0;
  text-align: left;
  background-color: green;
  color: white;
  padding: 10px;
}

body {
  text-align: center;
}

.container {
  margin: 10px auto;
}

利用BFC的内部规则4,可以轻松实现我们想要的效果,只需修改代码如下:
Css代码:

...

p {
  margin: 0;
  text-align: left;
  background-color: green;
  color: white;
  padding: 10px;
  overflow: hidden;
}

...

参考

  1. https://www.sitepoint.com/understanding-block-formatting-contexts-in-css/
  2. http://www.lxxyx.win/2016/02/06/寒假前端学习(8)——理解CSS浮动与清除浮动/
  3. https://www.zhihu.com/people/zhang-qiu-yi-27/answers