CSS-BFC

loading 2022年12月31日 168次浏览

1. 概念

BFC(Block formatting context)直译为"块级格式化上下文"。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。

在解释什么是BFC之前,需要先知道Box、Formatting Context的概念。

1.1 Box

Box 是 CSS 布局的对象和基本单位,一个页面是由很多个 Box 组成的。元素的类型和display属性决定了这个Box的类型。 不同类型的Box,会参与不同的Formatting Context(一个决定如何渲染文档的容器),因此Box内的元素会以不同的方式渲染。

  • block-level box:display 属性为 block, list-item, table 的元素,会生成 block-level box。并且参与 block fomatting context;
  • inline-level box:display 属性为 inline, inline-block, inline-table 的元素,会生成 inline-level box。并且参与 inline formatting context;
  • run-in box: css3中的概念。

1.2 Formatting Context

页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。最常见的 Formatting context 有 Block fomatting context (简称BFC)和 Inline formatting context (简称IFC)。

2. 布局规则

  • 内部的Box会在垂直方向,一个接一个地放置(即块级元素独占一行)。
  • BFC的区域不会与float box重叠(利用这点可以实现自适应两栏布局)。
  • 内部的Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠(margin重叠三个条件:同属于一个BFC;相邻;块级元素)。
  • 计算BFC的高度时,浮动元素也参与计算。
  • BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。

3. 创建BFC

  • float left/right
  • overflow的值不是visiable
  • display table-cell/table-caption/inline-block-inline-flex/flex
  • position的值不是static或者relative

4. 作用

4.1 解决margin塌陷/重叠问题

什么是margin的塌陷和重叠?塌陷是父子元素之间没有border/padding等内容时发生,重叠是兄弟元素之间垂直方向上发生。

4.1.1 父子元素塌陷

比如父元素包着一个子元素,会发现父子元素的上下边距合并为了一个外边距:

    #parent {
        width: 200px;
        height: 100px;
        background-color: lightgreen;
        margin: 20px auto;
        /* display: flex; */
    }

    .children {
        width: 50px;
        height: 50px;
        background-color: lightcyan;
        margin: 20px auto;
    }

    <div id="parent">
        <div class="children"></div>
    </div>

现在通过激活父元素的BFC,解决margin塌陷问题:

    #parent {
        width: 200px;
        height: 100px;
        background-color: lightgreen;
        margin: 20px auto;
        display: flex;
    }

4.1.2 兄弟元素重叠

两个p元素之间距离本该为200px,现在实际上只有100px,发生了margin重叠。

<style>
    p {
        background: #888;
        width: 200px;
        height: 100px;        
        margin: 100px;
    }
</style>

<body>
    <p>ABC</p>
    <p>abc</p>
</body>

可以通过在p外面包裹一层容器div,并触发生成BFC,那么两个P便不属于同一个BFC,就不会发生margin重叠问题了。

<style>
    p {
        background: #888;
        width: 200px;
        height: 100px;        
        margin: 100px;
    }
    div{
        overflow: hidden;
    }
</style>

<body>
    <p>ABC</p>
    <div>
        <p>abc</p>
    </div>
</body>

4.2 清除浮动

4.2.1 BFC清除浮动

子元素不设置浮动的情况下,当父元素不设置高度时,其高度会被子元素撑开。但是当子元素设为浮动元素时,由于子元素脱离了文档流,子元素原本的位置空间不被保留导致父元素高度为0,这就是高度塌陷现象。此时需要清除浮动:

<style>
    .father {
        border: 5px solid lightgreen;
	/* 激活父元素BFC清除浮动 */
        overflow: hidden;
    }
    .left {
        float: left;
    }
</style>
<body>
    <div class="father">
        <div class="left">我是float:left</div>
    </div>
</body>

4.2.2 伪元素清除浮动

这里顺便提一下剩下两种常用的清除浮动方式:

<style>
    .div1 {
        border: 5px solid lightgreen;
    }

    .div2 {
        height: 100px;
        width: 200px;
        background-color: lightblue;
        float: left;
    }
    /* 方法一 */
    .clearfix::after {
        content: "";
        display: block;
        clear: both;
        // 下面这两行似乎不一定要加
        visibility: hidden;
        height: 0;
    }
    
    /* 方法二 可以更好解决外边距重叠问题*/
    .clearfix::after,
    .clearfix::before {
        content: "";
        display: block;
        clear: both;
    }
</style>

<body>
    <div class="div1 clearfix">
        <div class="div2">div2</div>
    </div>
</body>

4.3 实现两栏布局

实现左侧定宽,右侧自适应。如果不激活右侧div的BFC,左侧浮动起来的div会把右侧div盖住。因此需要激活右侧BFC:

<style>
    .div1 {
        width: 100px;
        height: 150px;
        float: left;
        background: rgb(139, 214, 78);
    }

    .div2 {
        height: 300px;
        background-color: aquamarine;
        /* 激活BFC */
        overflow: hidden;  
    }
</style>

<body>
    <div class="div1">我是div1</div>
    <div class="div2">我是div2</div>
</body>