你所不知道的BFC

作者: Katherine的小世界 | 来源:发表于2017-09-08 22:12 被阅读143次

    真是一个小例子引发的“命案”呀,原本只是在想为什么一个容器内的块元素几个块元素会发生外边距(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。

    • float的值不是none.
    • position 的值不是static或者relative。
    • display的值是inline-block,table-cell,flex,table-caption或者inline-flex。(其实这个除了flex其他我好像都没用过)
    • overflow的值不是visible。

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

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

    • 1 BFC内的元素会导致 外边距合并。 (在BFC当中,盒子都是从它的包含块一个一个垂直放置的,两个相邻盒子的垂直间距取决于margin属性,所以两个相邻块会发生垂直外边距塌陷。)
    • 2 BFC中每一个盒子的左外侧紧贴包含块的左侧,(从右到左的格式里,则为盒子右侧紧贴包含快右侧)甚至有浮动也是如此。(浮动的元素是脱离文档流的,所以其他元素为将其当作不存在)。
    • 3 计算BFC的高度时,浮动元素也会计算进内。(所以,你懂的,我们可以给包含有浮动元素的父元素,设置成BFC,就可以 解决浮动元素导致的父元素坍塌的问题。
    • 4 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我们就一直有在使用,只是自己不知道而已。

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

    相关文章

      网友评论

      本文标题:你所不知道的BFC

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