BFC?

作者: LeoMelody | 来源:发表于2019-07-04 00:51 被阅读0次

BFC是前端面试中CSS部分的一个常考项,但是这个概念却是很不好理解的。

官方的定义

BFC (block formatting context) 块级格式化上下文。

在说BFC之前,先要说一下它的‘父亲’,FC(formatting context) 格式化上下文。FC用来表示页面中的某块区域是用什么格式来进行渲染布局的,常见的FC有: BFC,IFC(行级格式化上下文),GFC(网格布局格式化上下文)和FFC(自适应布局格式化上下文)。这四个好像是和display有着一些关系。由于我只对BFC有一些粗浅的理解,IFC,FFC,GFC这三个兄弟这里就不说了。

CSS视觉格式化模型与BFC

此处参考MDN

在说BFC之前必须要了解CSS视觉格式化模型。如果已懂可自行跳过。

CSS视觉格式化模型(visual formatting model)是用来将文档展示到视觉媒体上的计算规则,它会根据盒子模型将文档的元素生成一个个的盒子(Box)。

一个页面是由很多个的Box构成的,每一个Box都会有自己的类型,Box的类型取决于这个Box是个什么元素以及这个Box的display属性是什么。不同类型的Box就会有不同的FC来控制它的布局。所以,BFC也就是用来控制block-level的Box的是如何进行布局的。

下面解释几个定义

  • block-level box

块级盒子由块级元素(block-level element)生成。一个块级元素至少生成一个块级盒子,list-item除了自己的主块级盒子外,还有一个标记盒子。

-block-level element

块级元素,也就是display属性为 block,list-item,table的这些元素

OK,到这里已经会比较清晰的了解到BFC的作用范围了

更通俗的理解BFC

我看过很多的博客讲解BFC,但是还是更喜欢张鑫旭老师解释的。

一个BFC就像是一个结界一样,可以控制其内部的block-level Box不去影响结界外部的元素的正常布局。而这也是为什么我们要去使用BFC的原因(因为没有结界,一个包含块内的元素可能会影响其他元素的正常布局)。

那么,也就是说,不一定所有的块级盒子都会产生这个结界。

什么情况下会产生BFC呢?

  1. <html> 根元素 (最外层的结界)
  2. position 值是absolute或fixed (也就是说,在我们不设置特殊的position值时,都不会产生BFC)
  3. float 元素
  4. display值为 inline-block 、 table-cell、 table-caption (说实话后面俩好像都没用过)
  5. overflow的值不是visible
  6. flex的直接子元素以及grid的直接子元素

BFC下有哪些表现?

最基本的就是下面这五个特性:

  1. 内部的block-level Box会在垂直方向一个接一个的放置
  2. 上下margin重叠(取大值)
  3. 不同BFC下互不干扰布局
  4. 计算BFC高度时会将浮动元素也算入进去
  5. 不与浮动元素重叠(这个应该也是因为3)
  6. BFC内block-level Box在无padding,border的情况下,其内部box会将margin-top和margin-bottom(最上面和最下面的元素)转移到父元素且发生重叠。会一层一层往上转移知道有box具有padding和border属性。但是当父元素构成BFC时,无法转移
  • 案例1、文字环绕 (float真的是实现文字环绕效果很方便的一个手段)
/*css*/
  .wrap {
    width: 100px;
    background: red;
    color: aliceblue;
  }

  .float {
    float: left;
    width: 50px;
    height: 100px;
  }
// html
<div class="wrap">
    <div class="float">假装自己是个图片</div>
    <!-- <div class="text">我是一段很长很长的文字我是一段很长很长的文字我是一段很长很长的文字</div> -->
    <div class="text">我很短</div>
 </div>

看下面这两张图的比较:float可以导致父元素的高度崩塌,又因为行框盒子(这里指文字)和浮动元素的不可重叠性,所以在文字比较长时会有环绕的效果。

上面的父元素高度崩塌的解决方案也很简单,就是给文字的Box设置一个after伪元素。

.text::after {
  content: "";
  display: block;/*clear属性只作用在块级元素上*/
  clear: both;
}
long.png short.png

可不可以利用BFC达到相似的效果

 .wrap {
    display: inline-block;/*形成BFC*/
    width: 100px;
    background: red;
    color: aliceblue;
  }

因为4的原因,使得.wrap 元素形成BFC时高度会计算其内部的float元素,故解决了塌陷问题。

BFC1.png

这个可以说是一个很方便的解决方案

案例2、自适应两栏布局

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    .container {
      height: 100vh;
    }
    .menu {
      width: 200px;
      float: left;
      background: rgb(0, 255, 221);
      height: 100%;
      animation: changeW 3s infinite alternate;
    }
  /*模拟菜单拖拽*/
    @keyframes changeW {
      0% {
        width: 200px
      }

      100% {
        width: 500px;
      }
    }

    .content {
      overflow: hidden;
      height: 100%;
      background: rgb(238, 115, 8);
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="menu">我是菜单</div>
    <div class="content">我是内容</div>
  </div>
</body>
</html>

效果

这个就利用了3或者5的特性。现在由于flex布局的普及,可能我们不会再用这样的方法了。。。

案例3、外边距去哪了?

code:

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

   .normal {
      margin: 10px 0;
    }
    .son2 {
      margin: 10px 0;
    }

    .BFC {
      overflow: hidden;
    }
  </style>
</head>
<body>
  <div class="normal">
    <div class="son"></div>
  </div>
  
  <div class="BFC">
    <div class="son2">
      <div class="son2">
        <div class="son"></div>
      </div>      
    </div>
  </div>

  <div class="normal">
    <div class="son"></div>
  </div>

  <div class="normal">
      <div class="son"></div>
    </div>
</body>
</html>
效果图.png

效果解析:

如图,3,4两个box在垂直方向发生margin重叠间距只有10px符合BFC(此处为html根元素构成BFC)1,2两个特性

我在son和normal两个类均设置上下边距为10px,但是由于BFC中的6的特性,使得子元素上下外边距传递给父元素且发生重叠,最后两个.normal box之间的边距也就是为10px

最后,因为给.BFC box 设置overflow: hidden;使其构成BFC,让其直接子元素的上下外边距无法传递给自己,所以,这个box和其相邻box之间的边距变成了20px

结语

本文参考MDN文档以及张鑫旭老师的《CSS世界》一书。

相关文章

网友评论

    本文标题:BFC?

    本文链接:https://www.haomeiwen.com/subject/klthhctx.html