css的BFC

67 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情

FC -- Formatting Context

元素在标准流里面都是属于一个FC的:可能是block,也可能是inline。

Block-level boxes 属于BFC,inline-level boxes属于IFC

BFC -- Block Formatting Context

image.png

BFC的作用:

  • 在BFC中,box会在垂直方向上一个挨着一个的排布;
  • 垂直方向的间距由margin属性决定;
  • 在同一个BFC中,相邻两个box之间的margin会折叠
  • 在BFC中,每个元素的左边缘是紧挨着包含块的左边缘的;
<style>
        * {
            padding: 0;
            margin: 0;
        }
        .item {
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 30px;
            width: 50%;
            height: 100px;
            border: 1px solid red;
        } 
        .item:nth-child(odd) {
            background-color: #ccc;
        }
    </style>
</head>

<body>
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
    <div class="item">4</div>
    <div class="item">5</div>
</body>

image.png

为什么我们创建了五个div标签,他们会成这样排布呢?也就是为什么会什么会成竖直排布,他们会什么会紧挨着一起,他们为什么会排列在浏览器的左边呢?

这就是因为他们属于一个BFC里,他们都属于在html这个BFC里。所以在这个BFC里的所有box都会遵守上面的四条准则。

margin折叠

我们来看一个margin折叠问题

<style>
        * {
            padding: 0;
            margin: 0;
        }
        .item {
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 30px;
            width: 50%;
            height: 100px;
            border: 1px solid red;
        } 
        .item:nth-child(2) {
            background-color: #ccc;
            margin-top: 50px;
        }
        .item:nth-child(1) {
            background-color: #000;
            margin-bottom: 20px;
            color: #fff;
        }
    </style>
</head>

<body>
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
    <div class="item">4</div>
    <div class="item">5</div>
</body>

这里我们的第一个item的margin-bottom为20px,第二个item的margin-top为50px;按理来说,他们之间的距离应该有70px,但是真实结果呢?

image.png

我们发现第二个item的height为102px(height+margin-top+border),但是它是紧挨着第一个item的,按理来说他们应该还有着20px的距离。但是并没有。

结果就是: 在同一个BFC里,两个box之间如果有margin的话,那么他们之间总的margin取的是大的那一个,并不会两两相家。

那么如何解决呢?当然是靠BFC咯。

    <style>
        * {
            padding: 0;
            margin: 0;
        }

        .item {
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 30px;
            width: 50%;
            height: 100px;
            border: 1px solid red;
        }

        .item:nth-child(2) {
            background-color: #ccc;
            margin-top: 50px;
        }

        .item:nth-child(1) {
            background-color: #000;
            margin-bottom: 20px;
            color: #fff;
        }

        .father {
            overflow: auto;
        }
    </style>
</head>

<body>
    <div class="father">
        <div class="item">1</div>
    </div>
    <div class="item">2</div>
    <div class="item">3</div>
    <div class="item">4</div>
    <div class="item">5</div>
</body>

结果:

image.png

原因: 我们给第一个item外层嵌套一个div,这个div设置了一个属性overflow:auto;,这样就给.father这个div创造了一个新的BFC,这样第一个item个第二个item就没有在同一个BFC里了,他们就不会再发生margin合并了。

注:这个属性不一定要overflow:auto;看最上面我发的那张图,那些属性都可以创建一个新的BFC。

利用BFC解决浮动的高度塌陷问题

<style>
     * {
           padding: 0;
            margin: 0;
        }

        .container {
            background-color: orange;
        }

        .item {
            float: left;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 30px;
            width: 10%;
            height: 100px;
            border: 1px solid red;
        }

        .item:nth-child(odd) {
            background-color: #ccc;
        }

    </style>
</head>

<body>
    <div class="container">
        <div class="item">1</div>
        <div class="item">2</div>
        <div class="item">3</div>
        <div class="item">4</div>
        <div class="item">5</div>
    </div>
</body>

image.png

我们发现,container这个box容器的高度为0,这就是没有清除item的浮动,(浮动元素会脱离文档流,导致没有撑开父盒子)。

我们传统解决浮动的方法就是:内墙法。在浮动元素的后面加一个空的 块级元素 (通常是div),并且该元素设置 clear:both; 属性。clear属性,字面意思就是清除,那么both,就是清除浮动元素对我左右两边的影响。

    <style>
        * {
            padding: 0;
            margin: 0;
        }

        .container {
            background-color: orange;
        }

        .clearfix {
            clear: both;
        }

        .item {
            float: left;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 30px;
            width: 10%;
            height: 100px;
            border: 1px solid red;
        }

        .item:nth-child(odd) {
            background-color: #ccc;
        }
    </style>
</head>

<body>
    <div class="container">
        <div class="item">1</div>
        <div class="item">2</div>
        <div class="item">3</div>
        <div class="item">4</div>
        <div class="item">5</div>
        <div class="clearfix"></div>
    </div>
</body>

image.png

但是我们也可以使用BFC的方法进行清除浮动。

<style>
        * {
            padding: 0;
            margin: 0;
        }

        .container {
            background-color: orange;
            overflow: hidden;
        }

        .item {
            float: left;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 30px;
            width: 10%;
            height: 100px;
            border: 1px solid red;
        }

        .item:nth-child(odd) {
            background-color: #ccc;
        }
    </style>
</head>

<body>
    <div class="container">
        <div class="item">1</div>
        <div class="item">2</div>
        <div class="item">3</div>
        <div class="item">4</div>
        <div class="item">5</div>
    </div>
</body>

image.png

我们发现这也成功清除了浮动。

但是,这是有一个条件的:那就是父元素的高度为aoto

BFC清除浮动的原理:

BFC的高度是auto的情况下,是如下方法计算高度的:

  • 如果只有inline-level,是行高的顶部和底部的距离;
  • 如果有block-level,是由最底层的块上边缘和最底层块盒子的下边缘之间的距离;
  • 如果有绝对定位元素,将被忽略;
  • 如果有浮动元素,那么会增加高度以包括这些浮动元素的下边缘。