BFC详解

98 阅读4分钟

什么是BFC

块格式化上下文(Block Formatting Context, 简称BFC)是Web页面的可视CSS渲染的一部分,是块级盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。

BFC具有以下几个特点:

  1. BFC是一个独立的布局环境,BFC内部的元素布局与外部互不影响
  2. 可以通过一些条件触发BFC,从而实现某些特殊的布局

BFC布局规则

BFC布局在布局时会遵从以下规则:

  1. 内部的块级元素会在垂直方向上一个接一个地排列(也是文档流的规则)
  2. 块级元素垂直方向的距离由margin决定。属于同一个BFC的两个相邻的块级元素会发生margin合并;不属于同一个BFC的两个相邻的块级元素不会发生margin合并。(可以用来解决margin重叠)
  3. 每个元素的margin box的左边,与包含border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是这样的
  4. BFC的区域不会与float box重叠。
  5. BFC就是页面上的一个隔离的独立容器,容器里面的元素不会影响到里面的元素,里面的元素也不会影响到外面的元素。
  6. 计算BFC的高度时,浮动元素也参与计算。(可以用来解决浮动导致的父元素高度塌陷的问题)

BFC形成的条件

  • 根元素html
  • 浮动元素的float属性不为none
  • 块元素的overflow属性不为visiable和clip
  • 绝对定位元素的position属性为absolute或fixed
  • 行内块元素(也就是display: inline-block;)
  • 表格单元格元素(也就是display: table-cell;)
  • 表格标题元素(也就是display: table-caption;)
  • 匿名表格单元格元素(也就是display: table或table-row或table-row-group或table-header-group或table-footer-group;)
  • display值为flow-root的元素
  • contain值为layout、content或paint的元素
  • 弹性元素(display 值为 flex 或 inline-flex 元素的直接子元素),如果它们本身既不是 flex、grid 也不是 table 容器
  • 网格元素(display 值为 grid 或 inline-grid 元素的直接子元素),如果它们本身既不是 flex、grid 也不是 table 容器
  • 多列容器(column-count 或 column-width (en-US) 值不为 auto,包括column-count 为 1)

BFC的应用

正是因为BFC具有以上介绍的特点以及它在页面布局时遵循的规则,因此BFC常常被用于以下几个方面

解决浮动导致的高度塌陷(包含内部浮动)

<div class='test-wrap'>
  <!-- BFC布局 -->
  <div class="box">我是一个块级盒子</div>
</div>
.test-wrap {
  width: 400px;
  border: 1px solid black;
  .box {
    width: 200px;
    height: 200px;
    float: left;
    border: 1px solid lightgreen;
  }
}

效果如下: image.png

父容器发生了高度塌陷

给父容器设置一个生成BFC的属性,这里我们设置的是overflow: hidden;

<div class='test-wrap'>
  <!-- BFC布局 -->
  <div class="box">我是一个块级盒子</div>
</div>
.test-wrap {
  width: 400px;
  border: 1px solid black;
  overflow: hidden;
  .box {
    width: 200px;
    height: 200px;
    float: left;
    border: 1px solid lightgreen;
  }
}

效果如下:

image.png

解决margin传递的问题

<div class='test-wrap'>
  <!-- BFC布局 -->
  <div class="box"></div>
</div>
.test-wrap {
  width: 100px;
  height: 100px;
  background-color: red;
  .box {
    width: 50px;
    height: 50px;
    margin-top: 50px;
    background-color: blue;
  }
}

效果如下 image.png

明明是给子元素设置的margin-top,却传递给了父元素,变成了父元素有margin-top.

给父容器设置一个生成BFC的属性,这里我们设置的是display: inline-block;

效果如下: image.png

不发生margin传递了。

解决块级元素margin重叠

<div class='test-wrap'>
  <!-- BFC布局 -->
  <div class="box1">我是第一个块级盒子</div>
  <div class="box2">我是第二个块级盒子</div>
</div>
.test-wrap {
  width: 400px;
  height: 500px;
  background-color: aliceblue;
  .box1 {
    height: 100px;
    border: 1px solid lightgreen;
    margin-bottom: 30px;
  }
  .box2 {
    height: 100px;
    border: 1px solid lightblue;
    margin-top: 20px;
  }
}

效果如下:

image.png

两个盒子之间的距离只有30px,margin发生了重叠

给两个盒子加一层容器,然后设置生成BFC的属性,这里我们设置的是overflow: hidden;使其成为两个独立的BFC,这样就不会重叠了

<div class='test-wrap'>
  <!-- BFC布局 -->
  <div class="container">
    <div class="box1">我是第一个块级盒子</div>
  </div>
  <div class="container">
    <div class="box2">我是第二个块级盒子</div>
  </div>
</div>
.test-wrap {
  width: 400px;
  height: 500px;
  background-color: aliceblue;
  .box1 {
    height: 100px;
    border: 1px solid lightgreen;
    margin-bottom: 30px;
  }
  .box2 {
    height: 100px;
    border: 1px solid lightblue;
    margin-top: 20px;
  }
  .container {
    overflow: hidden;
  }
}

效果如下: 两个盒子之间的距离是50px

自定义两栏布局(排除外部浮动)

<div class='test-wrap'>
  <!-- BFC布局 -->
  <div class="left-box">我是左边盒子,内容是巴拉巴拉巴拉巴拉巴拉巴拉</div>
  <div class="right-box">我是右边盒子</div>
</div>
.test-wrap {
  width: 400px;
  height: 400px;
  border: 1px solid red;
  .left-box {
    width: 100px;
    height: 100px;
    float: left;
    background-color: lightblue;
  }
  .right-box {
    background-color: lightcoral;
  }
}

效果如下: image.png

此时浮动元素会遮挡右边的元素

给右边元素设置一个生成BFC的属性,这里我们设置的是display:flow-root

<div class='test-wrap'>
  <!-- BFC布局 -->
  <div class="left-box">我是左边盒子,内容是巴拉巴拉巴拉巴拉巴拉巴拉</div>
  <div class="right-box">我是右边盒子</div>
</div>
.test-wrap {
  width: 400px;
  height: 400px;
  border: 1px solid red;
  .left-box {
    width: 100px;
    height: 100px;
    float: left;
    background-color: lightblue;
  }
  .right-box {
    background-color: lightcoral;
    display:flow-root;
  }
}

效果如下: image.png

这样右边盒子就不会被左边盒子遮挡了。这个对应了BFC布局规则的第四点。