BFC的利弊 --垂直边距塌陷与清除浮动

17 阅读3分钟

BFC

BFC 是 Block Formatting Context 的缩写,是 CSS 布局中一个非常重要的概念。它是一个独立的渲染区域,只有块级盒子参与,形成一个封闭的环境,内部的元素不会影响外部的元素,反之亦然。BFC 在解决 CSS 布局的一些常见问题时非常有用,例如清除浮动和防止元素重叠

BFC 如何被创建

  • 根元素(html),或包含body的元素

  • floatleft、right

  • positionabsolutefixed

  • displayinline-blocktable-celltable-captionflex

  • overflowauto、scroll、hidden

常用方式: display:tableoverflow: hidden

⚠️ 同一个BFC下的垂直相邻外边距会发生重叠

相邻的两个盒子(可能是兄弟关系也可能是祖先关系)的垂直外边距 相邻时, 它们将形成一个外边距。这个外边距的高度等于两个发生折叠的外边距的高度中的较大者。

  1. 两个相邻的外边距都是 正数 时,折叠外边距是两者中较大的值
  2. 两个相邻的外边距都是 负数 时,折叠外边距是两者中绝对值较大的值
  3. 两个相邻的外边距是 一正一负 时,折叠外边距是两者相加的和
相邻的意思是说:没有设置padding,border或者行内内容等来隔开两个外边距。

1. 父与子元素垂直边距重叠

方式一:

<div class="box1"></div>
<div class="box3">
  <div class="box4"></div>
</div>

.box1 {
  width: 100px;
  height: 100px;
  background-color: blue;
}
.box3 {
  width: 200px;
  height: 200px;
  background-color: red;
  margin-top:50px;
}
.box4 {
  width: 100px;
  height: 100px;
  background-color: mediumseagreen;
  margin-top: 100px;
}
.box3:before {
    content: '';
    display: table; (触发BFC)
}

2. 父元素高度塌陷问题

<code class="language-plaintext hljs"><div class='container'>
  <div class='box1'>
    box1
  </div>
</div>
<style>
  .container{
    background: deepskyblue;
    border: 2px solid greenyellow;
  }
  .box1{
    width: 100px;
    height: 100px;
    background: red;
    float: left;
  }
</style>
</code>

3. 兄弟元素垂直边距重叠

方式一:给其中一个元素包裹一层,例如:div1包裹一个div container,并开启BFC

<code class="language-plaintext hljs">
<div class='container'>
  <div class='box1'>
    box1
  </div>
</div>
<div class='box2'>
  box2
</div>

<style>
  .container{
    overflow: hidden;(#BFC触发)
  }
  .box2{
    width: 100px;
    height: 100px;
    background: deepskyblue;
    margin-top: 50px;
  }
  .box1{
    width: 100px;
    height: 100px;
    background: red;
    margin-bottom: 100px;
  }
</style></code>

方式二: 直接在元素内部设置 display:inline-block

<code class="language-plaintext hljs">
<div class='box1'>
  box1
</div>
<div class='box2'>
  box2
</div>
<style>
  .box2{
    width: 100px;
    height: 100px;
    background: deepskyblue;
    margin-top: 50px;
    display: inline-block;(#BFC触发)
  }
  .box1{
    width: 100px;
    height: 100px;
    background: red;
    margin-bottom: 100px;
    border: 1px solild #fff;(设置边框)
    padding-top1px(设置padding)
  }
</style></code>

.clearfix:before,
.clearfix:after{
    content: "";
    display: table;
    clear: both;
}
/*
before伪元素解决外边距重叠问题 使父子元素的外边距不相邻
after伪元素解决高度塌陷 添加一个清除浮动的伪元素来撑起父元素
*/

BFC带来的好处,清除浮动

1. 使用清除元素

在浮动元素后面添加一个带有 clear 属性的元素,可以清除浮动。

<!DOCTYPE html>
<html>
<head>
    <style>
        .container {
            width: 300px;
            border: 1px solid black;
        }
        .box {
            float: left;
            width: 100px;
            height: 100px;
            background-color: lightblue;
        }
        .clear {
            clear: both;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="box">Box 1</div>
        <div class="box">Box 2</div>
        <div class="clear"></div> <!-- 清除浮动 -->
    </div>
</body>
</html>

2. 使用 overflow 属性

设置容器的 overflow 属性为 hiddenautoscroll,可以让容器包含浮动的子元素。

html
<!DOCTYPE html>
<html>
<head>
    <style>
        .container {
            width: 300px;
            border: 1px solid black;
            overflow: hidden; /* 清除浮动 */
        }
        .box {
            float: left;
            width: 100px;
            height: 100px;
            background-color: lightblue;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="box">Box 1</div>
        <div class="box">Box 2</div>
    </div>
</body>
</html>

3. 使用 flexbox 布局

如果不介意使用更现代的布局方式,可以使用 display: flex,它天然清除浮动。

<!DOCTYPE html>
<html>
<head>
    <style>
        .container {
            display: flex;
            width: 300px;
            border: 1px solid black;
        }
        .box {
            width: 100px;
            height: 100px;
            background-color: lightblue;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="box">Box 1</div>
        <div class="box">Box 2</div>
    </div>
</body>
</html>