Vue.js学习Web前端之路让前端飞

你所不知道的BFC

2017-09-08  本文已影响143人  Katherine的小世界

真是一个小例子引发的“命案”呀,原本只是在想为什么一个容器内的块元素几个块元素会发生外边距(margin collapse),然后找啊找啊找,就找到了BFC(Block Formating context)。> 真是很福气自己,被自己感动哭了

首先,我会从 BFC是什么? 如何形成BFC? BFC的应用 这三个方面入手。


1 BFC 是什么?

BFC 是web页面中盒模型布局中的CSS渲染模式,定位机制属于普通流模式。
一个块格式化上下文(block formatting context) 是Web页面的可视化CSS渲染出的一部分。它是块级盒布局出现的区域,也是浮动层元素进行交互的区域。

(我们都知道,CSS中的定位机制有三种形式:1 普通流模式 2 浮动 3 定位。)BFC其实就是一个独立的布局环境,其中的元素不受外界影响。> 我知道你现在看到这里肯定还不知道我在说什么,说实话,我一开始看其他文章也是这样的,还是继续往下看,回头再来理解概念吧。

2 创建BFC

一个元素要创建BFC,需要满足以下几个条件,才能形成BFC。

所以,只要满足以上四个条件就可以创建BFC了,但是,等等,我们要创建BFC干嘛?首先应该知道BFC的实际用处,我们才会在实际应用中使用它。那么接下来就是,BFC的作用,我会用好多个例子来证明一下。

3 BFC的特性 (人家虽然好用,也是有缺点的,例如外边距合并问题)

BFC元素不会与浮动元素重合。 我需要说明一点就是,这是一个清除浮动的很好的方式啊啊啊。
1 当一个容器中有一个左浮动元素和一个BFC元素的时候,BFC的宽度如果可以在剩余空间存放的话,就会显示在浮动元素所在行的剩余空间内。
2 当 BFC 的宽度大于容器剩余宽度时,最新版本的浏览中只有firefox会在同一行显示,其它浏览器均换行。

是不是有点晕了,这个时候最好不要放弃,继续往下看,重头戏还在后头,知道了这些基础的东西之后,我们需要知道一些关于BFC的实践应用和基本原理。

4 BFC 实践及其原理。

1 自适应两栏布局 (原理参照:BFC的第4条属性。)

先看下面的代码:

CSS部分:
   <style>
      .container {
          width:400px;
          margin:200px;
      }
      .leftpart {
          float: left;
          width:100px;
          height:200px;
          background: plum;
          color: white;
      }
      .rightpart {
          height:300px;
          background: pink;
          color: white;
      }
  </style>
html部分:
<body>
  <div class="container">
      <div class="leftpart">我是左边的那一块</div>
      <div class="rightpart">我是右边的那一块,听说我会环绕在左边的浮动元素上,我也是没办法啊,因为浮动元素是脱离文档流的,我谁将它当作不存在,然后占据他所在的空间呢
      也只有将我设置成BFC的形式,我才不会这样呢?不信你试一试</div>
  </div>
</body>

左边的设置了左浮动,因为浮动元素脱离文档流,所以结果会是下面这个样子。

image.png

很显然,这不是我们想要的结果,前面提到了BFC的特性中,有一条提到,BFC不会与浮动元素触碰,那么我们是不是可以给右边的元素设置成BFC。
那么其实,就是在.rightpart设置多一个样式属性就可以了。

.rightpart {overflow:auto;}    // 前面提到了如何形成一个BFC,可以设置overflow不为visible。

那么,我们来看看效果图。

image.png

这样,我们右边的那一块,没有设置宽度,会自动根据容易的宽度还有浮动元素的宽度,自适应的分配宽度给右边那一块。这样也给我们的自适应布局提供了思路呀。
对了,如果希望左右两栏有间距,你可以这么做。
你会发现,你给右边那一块设置了margin-left之后,并没有你理想中那样。假设我添加了

.rightpart {margin-left:20px;}  // 只是设置了20

你会发现。这两栏看上去还是没有间距的。其实从下图可以发现,不是margin不起作用。

image.png

我的理解是,margin-left确实是起作用了,但是它其实还是将浮动元素看做是不占据文档流的,只是BFC元素的盒模型中border内的不再去抢浮动元素的空间,但是margin还是会抢占浮动元素的空间的。所以,要想看到两栏有间距,需要设置的margin-left要大于leftpart的宽度。
(当然,这并不是明智之举,要是你不知道leftpart的宽度,岂不是悲剧了)

试一下:

.rightpart {margin-left:120px;}  // 只是设置了120
image.png

其实,不用那么麻烦。我们只需要给 leftpart设置margin-right 就可以了。
上面其实也只是想详细的去理解这个过程。

.leftpart {margin-right:20px;}
image.png

不知道你有没有发现,如果我们之前不设置BFC的话,也就是不给rightpart设置成BFC的话,直接就是设置rightpart的margin-left大于左浮动元素的宽度,也可以达到两栏布局的效果,但是,~~~那样很麻烦啊,如果不知道宽度怎么办。

所以,两栏布局的最佳实践应该是: margin-left + BFC模式。
(当然,用flex布局会更加方便,但是这也不失为一种好方法呀。)

2 解决含有浮动元素的父元素塌陷问题

首先,这个问题的存在原因是因为浮动元素是脱离文档流的,所以包裹浮动元素的父元素其实并不能被撑开,所以就会导致下面的结果,看一下图。

image.png

上例所示图的代码如下:

// 很明显,两个子模块的定位都是浮动形式,而父元素发生了坍塌。
html部分:
<body>
    <div class="mainPart">
        <div class="testpart"></div>
        <div class="testpart"></div>
    </div>
</body>

CSS部分:
       .mainPart {
            background: royalblue;
            border:1px solid olivedrab;
            width:500px;
        }
        .testpart {
            float: left;
            width:200px;
            height:200px;
            background: plum;
            margin:10px;
        }
那么?怎么解决这个问题。

当然。你可以向通常的清除浮动的方法一样,在父元素内部添加一个空元素,设置clear:both;可以达到清除浮动的效果。

那如何通过设置一个BFC去清除浮动呢?

前面第3点中提到:
计算BFC的高度时,浮动元素也会计算进内。

所以,可以将父元素设置成BFC,就可以达到清除浮动,清除高度坍塌问题。

// 给父元素添加以下样式
   .mainPart {
          overflow:auto;
        }

那么,效果如下图:

image.png

所以,可以通过给父元素设置成BFC来清除浮动。

3 BFC内部元素外边距塌陷问题解决。

前面提到的BFC的原理特性中,有一个就是外边距合并问题。(这又是一个大boss,我最近也在看这方面的资料,后续会补上详细的笔记的)

BFC垂直方向上的距离由margin值所决定,同一个BFC内的两个相邻元素的margin值会重叠。

什么意思捏~~~~
先看下图:

image.png

其实两个粉色的子元素,已经设置了margin值为20了。按照道理来说的话,上下两块之间的距离应该是40的。但是这里只是20.也就是外边距合并最后是取比较大的那一个。
(其实我想了一下,我觉得这个外边距合并用在这里挺好的呀,有时候如果我们想实现下面这样一个效果,其实我觉得外边距合并的存在反倒是好的呢)
只需要给每一个子元素设置margin为20即可。(当然,父元素和第一个子元素以及最后一个子元素也会发生合并问题, ~~啊啊啊,我后面会贴上一文章来解释的,~~)

image.png

针对这种子元素发生外边距合并的处理方法。
我们可以将子元素重新设置成一个BFC就可以了。
你想想,一开始,在同一个BFC下的子元素之所以会发生垂直外边距合并(对了,外边距合并只发生在垂直方向,水平方向不会的。),是因为父元素的高度是由子元素决定的,所以高度也会发生外边距合并了。
解决方法就是,用一个元素给第二个子元素包在一个新的BFC内。

html部分:
<div class="father">
    <div class="son"></div>
    <div style="overflow: auto">    // 这里设置了父元素,同时设置overflow:auto。
        <div class="son" ></div>
    </div>
</div>
CSS部分:
  .father {
            width:100px;
            height:200px;
            background: red;
            /*margin:20px;*/
        }
        .son {
            width:30px;
            height:90px;
            margin: 20px;
            background: plum;
        }

这样的话,结果就如下所示了:

image.png

后记: 我理解的BFC其实就是CSS中的一个渲染机制,BFC就相当于一个盒子,内部的元素与外界的元素互不干扰。它不会影响外部的布局,外部的布局也不会影响到它。你想一下,为什么设置了BFC之后就可以清除浮动,我的理解就是,设置了BFC之后的元素就是一个独立的个体,内部有浮动元素也不会再影响外部的元素了。那为什么设置了BFC之后,不会发生对周围元素的环绕现象,也是同一个道理。所以,这么去想一想,其实BFC我们就一直有在使用,只是自己不知道而已。

总算写完了,有时候觉得自己理解和写出来是完全两码事的东西,希望自己能够继续坚持吧。希望能够帮助到你们,也欢迎一起交流。
上一篇下一篇

猜你喜欢

热点阅读