布局概念---深入理解BFC

707 阅读5分钟

深入理解CSS中的BFC:一文掌握块级格式化上下文

前言

在CSS布局中,BFC(Block Formatting Context,块级格式化上下文)是一个非常重要却又常被忽视的概念。它像是CSS世界中的一个结界,为元素提供了独立的渲染环境。本文将深入浅出地讲解BFC的概念、触发条件及实际应用,帮助你更好地掌握CSS布局技巧。

什么是BFC?

BFC(Block Formatting Context)是Web页面中的一个独立渲染区域,它有自己的一套渲染规则:

内部的盒子会在垂直方向上一个接一个排列

同一个BFC中的相邻元素margin会发生重叠

BFC区域不会与float元素重叠

计算BFC的高度时,浮动元素也参与计算

BFC是一个独立的容器,容器内部元素不会影响外部元素

简单来说,BFC就是一个"结界",内部元素的布局不会影响外部,外部元素也不会影响内部布局。

BFC的触发条件

以下情况会触发BFC:

  1. 根元素<html>是页面中最大的BFC
  2. 浮动元素:float值不为none
  3. 绝对定位元素:position为absolute或fixed
  4. 行内块元素:display为inline-block
  5. 表格单元格:display为table-cell
  6. 表格标题:display为table-caption
  7. overflow不为visible:overflow为hidden、auto或scroll
  8. 弹性盒子:display为flex或inline-flex
  9. 网格布局:display为grid或inline-grid

在实际开发中,最常用的触发BFC的方法是设置overflow: hidden

BFC的应用场景

1. 使用Float脱离文档流,高度塌陷

在弹性布局出现之前,我们常用浮动来实现多列布局。但浮动会导致父元素高度塌陷的问题。通过将父元素设置为BFC,可以清除浮动影响:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>高度塌陷</title>
    <style>
      .box {
        margin: 100px;
        width: 100px;
        height: 100px;
        background: pink;
        float: left;
      }
      .container {
        background: #000;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="box"></div>
      <div class="box"></div>
    </div>
  </body>
</html>

可以看到效果图:

image.png

可以看到上面的效果给box设置float结果脱离文档流,使container高度没有被撑开,导致背景颜色没有处理啊,解决此问题可以给container触发BFC,上面触发BFC属性都可以设置。浅浅加一个overflow:hidden;吧。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>高度塌陷</title>
    <style>
      .box {
        margin: 100px;
        width: 100px;
        height: 100px;
        background: pink;
        float: left;
      }
      .container {
        background: #000;
        overflow: hidden;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="box"></div>
      <div class="box"></div>
    </div>
  </body>
</html>

image.png

2. 解决外边距垂直坍塌

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>高度塌陷</title>
    <style>
      .box1 {
        margin: 10px;
        width: 100px;
        height: 100px;
        background: pink;
      }

      .box2 {
        margin: 50px;
        width: 300px;
        height: 300px;
        background: yellowgreen;
      }
    </style>
  </head>

  <body>
    <div class="container">
      <div class="box1"></div>
      <div class="box2"></div>
    </div>
  </body>
</html>

效果图: image.png

可以发现显示出来的两个盒子之间的距离只有50px的距离(边距坍塌时取最大的那个margin),这就导致了margin塌陷问题,这时margin边距的结果为最大值,而不是margin之和。解决该问题可以给这两个盒子都添加一个父元素,并且将这个元素设置为BFC区域,这样就产生了两个独立的个体不会相互影响,这样就可以解决margin坍塌的问题了。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>高度塌陷</title>
    <style>
      .box1 {
        margin: 10px;
        width: 100px;
        height: 100px;
        background: pink;
      }

      .box2 {
        margin: 50px;
        width: 300px;
        height: 300px;
        background: yellowgreen;
      }
      .container {
        overflow: hidden;
      }
    </style>
  </head>

  <body>
    <div class="container">
      <div class="box1"></div>
    </div>
    <div class="container">
      <div class="box2"></div>
    </div>
  </body>
</html>

这样两个盒子之间的距离就变成了margin之和。

3. 自适应两栏布局

BFC不会与浮动元素重叠的特性,可以用来实现自适应两栏布局:

<div class="container">
  <div class="aside"></div>
  <div class="main"></div>
</div><style>
.container {
  width: 100%;
}
.aside {
  float: left;
  width: 200px;
  height: 300px;
  background: #f00;
}
.main {
  overflow: hidden; /* 触发BFC */
  height: 300px;
  background: #0f0;
}
</style>

在这个例子中,.main元素触发了BFC,它不会与浮动的.aside元素重叠,从而形成了自适应的两栏布局。

4.解决包含坍塌

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>包含坍塌</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }

      .container {
        background: pink;
        width: 300px;
        height: 300px;
      }

      .box {
        background: yellow;
        width: 100px;
        height: 100px;
        margin: 50px;
      }
    </style>
  </head>

  <body>
    <div class="container">
      <div class="box"></div>
    </div>
  </body>
</html>

image.png

当我们给子元素添加margin时,会带着父盒子一起移动。但是我们只想要子元素距离父元素50px,而不是带着父元素一起移动,这个时候我们用BFC也可以解决该问题

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>包含坍塌</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }

      .container {
        background: pink;
        width: 300px;
        height: 300px;
        /* 开启BFC */
        overflow: hidden;
      }

      .box {
        background: yellow;
        width: 100px;
        height: 100px;
        margin: 50px;
      }
    </style>
  </head>

  <body>
    <div class="container">
      <div class="box"></div>
    </div>
  </body>
</html>

image.png

5.避免被浮动元素覆盖

浮动元素会脱离文档流,跑到另一个平面,与原来文档流中的元素不在同一平面中,会导致覆盖掉其它的元素。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .box1 {
        background: pink;
        height: 200px;
      }

      .box2 {
        background: yellowgreen;
        width: 100px;
        height: 100px;
        float: left;
      }
    </style>
  </head>

  <body>
    <div class="box2"></div>

    <div class="box1"></div>
  </body>
</html>

image.png 可以看到黄绿色的小方块浮动在粉色的长方条的上方,现在只需要将box1设置为BFC,此时box1即为一个独立的个体,就不会受到浮动的影响了。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .box1 {
        background: pink;
        height: 200px;
        /* 开启BFC */
        overflow: hidden;
      }

      .box2 {
        background: yellowgreen;
        width: 100px;
        height: 100px;
        float: left;
      }
    </style>
  </head>

  <body>
    <div class="box2"></div>

    <div class="box1"></div>
  </body>
</html>

image.png

BFC与其他布局方式的比较

在早期,我们常用float来实现多列布局,但float会让元素脱离文档流(虽然不是完全脱离)。随着flex布局的普及,现在我们有了更好的选择:

  1. Float布局:需要清除浮动,处理高度塌陷问题
  2. BFC布局:可以包含浮动,防止外边距重叠
  3. Flex布局:更加灵活,易于使用,是现代布局的首选
  4. Grid布局:二维布局系统,适合复杂的网格设计

相比之下,BFC更像是一种CSS机制,而不仅仅是一种布局方式。了解BFC有助于我们解决一些常见的CSS问题。

总结

BFCCSS中的一个重要概念,理解并掌握它的特性可以帮助我们解决多种布局问题:

清除浮动

防止外边距折叠

实现自适应布局

在实际开发中,虽然现在我们有了flexgrid这些更强大的布局工具,但BFC的概念和应用依然是每个前端开发者应该掌握的基础知识。

希望这篇文章能帮助你更好地理解BFC,在CSS布局中游刃有余!