什么是BFC

BFC概念

BFC(Block formatting context)直译为“块级格式化上下文”,只有块级的盒子参与,内部规定了块级盒子如何布局。

BFC是一个独立的布局环境,其中的元素布局是不受外界的影响。

display属性为block、table、list-item的元素默认会产生BFC。也可以手动创建,如果将一个div(默认为块级元素,即本身拥有BFC)设置为inline-block,会产生一个的BFC。

如何创建BFC

  1. float属性不为none
  2. position属性为absolute或fixed
  3. display为inline-box、flex、inline-flex、table-cell
  4. overflow不为visible

BFC布局特性

  1. 在BFC中,盒子从顶端开始垂直往下排列
  2. 盒子垂直方向的间距由margin决定,属于同一个BFC的两个相邻的盒子margin会发生重叠
  3. 在BFC中,每一个盒子的左外边缘(margin-left)会触碰到容器的左内边缘(border-left
  4. BFC的区域不会与浮动盒子产生交集,而是紧贴浮动边缘
  5. 在计算BFC的高度时,也会检测浮动或定位的盒子高度

BFC的作用

  1. 清除浮动
    只要把父元素设置为BFC,就可以清除子元素的浮动了,如:常使用 overflow:hidden

    1
    2
    3
    <div>
    <p>1</p>
    </div>
    1
    2
    3
    4
    5
    6
    div{}
    p {
    width: 200px;
    line-height: 100px;
    text-align: center;
    }

    我们可以给div设置以下这些样式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    div{
    /*推荐第一种*/
    overflow: hidden;
    overflow: auto;
    display: flex;

    /* 可以解决p的浮动问题,但同时增加了div自己的浮动问题 */
    float: left;

    /* 可以解决p的浮动问题,但是同时让div没有宽度,只是被p给撑起来了 */
    display: inline-block;
    display: table-cell;
    display: inline-flex;
    position: absolute;
    position: fixed;
    }
  2. 解决外边距合并问题
    只要创建不属于同一个BFC,外边距就不会发生合并,如:

    1
    2
    <p>1</p>
    <p class="p2">2</p>
    1
    2
    3
    4
    5
    6
    7
    p {
    width: 200px;
    line-height: 100px;
    text-align: center;
    background-color: #f00;
    margin: 30px;
    }

    有两个p(块级元素,本身拥有同一个BFC),都设置 marign 时,默认p1的 marign-bottom 和p2的 margin-top 会发生合并,只表现出一个30px的间距。

    如何解决呢?可以让p2产生一个新的BFC,只要不p1、p2不属于同一个BFC,margin 就不会发生合并。

    1
    2
    3
    4
    5
    6
    7
    .p2{
    float: left;
    display: inline-block;
    display: inline-flex;
    position: absolute;
    position: fixed;
    }

    以上这些属性都可以直接作用于某个盒子本身,然后产生一个新的BFC。当然也可以有更多的办法:

    1
    2
    3
    4
    <p>1</p>
    <div>
    <p>2</p>
    </div>

    使用div包裹p2,然后给div这个父级设置样式,这个时候就有了更多的选择,任选一种即可。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    div{
    float: left;
    display: inline-block;
    display: inline-flex;
    position: absolute;
    position: fixed;
    /* 除了上面这些,还可添加这些作用于父级的样式 */
    overflow: hidden;
    overflow: auto;
    display: flex;
    display: table-cell;
    }
  3. 自适应两列布局
    根据特性3: 每一个盒子的左外边缘(marigin)会触碰容器的左内边缘(border-left),即使是浮动元素。

    1
    2
    <div class="left">LEFT</div>
    <div class="right">RIGHT</div>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    body{
    border: 5px solid #f00;
    }
    .left {
    width: 100px;
    height: 150px;
    float: left;
    background: #0f0;
    text-align: center;
    line-height: 150px;
    font-size: 20px;
    margin: 5px;
    }
    .right {
    height: 300px;
    background: #00f;
    text-align: center;
    line-height: 300px;
    font-size: 40px;
    }

    从下图可以看出:left的margin-left外边缘(蓝色margin 5px左侧)和父级容器(body)的border-left(红色border 5px内侧)内边相触碰。

    再根据特性4:BFC的区域不会与浮动盒子产生交集,而是紧贴浮动边缘。
    让right单独成一个BFC,添加样式:

    1
    2
    3
    .right{
    overflow: hidden;
    }

    这样就实现两列布局了,并且right布局可以自适应。