普通视图

发现新文章,点击刷新页面。
昨天 — 2025年2月21日首页

页面渲染规则之BFC

作者 不是鱼
2025年2月21日 00:35

前言

我们的css中有许多页面渲染规则,它是浏览器用来解释和显示网页样式的一系列原则,决定了元素如何在页面上呈现。比如说:选择器优先级层叠机制继承盒模型流布局视觉格式化模型媒体查询css动画和转换性能优化等等,今天我们重点讲讲属于视觉格式化模型中的BFC,是面试中高频的考查部分。

盒模型

我们先来唠唠盒模型。在css中我们有两种盒模型,分别是:标准盒模型和IE盒模型,我们在实际开发中可以选择适合的盒模型进行使用,在现代浏览器中,默认使用的盒模型是标准盒模型。我们来看看它们两者的区别:

    <style>
        *{
            margin: 0;
            padding: 0;
        }
        /* 盒模型 + 块级  */
        .box,.box2,.box3{
            width: 100px;
            height: 100px;
            padding: 10px;
            border: 1px solid red;;
            background-color: green;
        }
        .box2{
            /* border 以内盒子的大小(包括border)IE 怪异盒模型*/
            box-sizing: border-box;
        }
        .box3{
            /* 默认值,标准盒模型 wh 设置的就是 content 的大小*/
            box-sizing: content-box;
        }
    </style>
</head>
<body>
    <div class="box"></div>
    <div class="box2"></div>
    <div class="box3"></div>
</body>

在这里我们加入了三个盒子,其中box1box3是标准盒模型,box2是IE盒模型,我们给它们都设置了width:100px;height:100px;来看看它们在页面中的效果:

image.png

为什么大小会不一样呢,打开浏览器的开发者工具检查一下,点击我们的box1box3,可以看到:

image.png

我们设置的宽高只是内容的宽高,也就是content,并不包括padding,border,那box2呢:

image.png

我们可以发现它的content + padding +border加起来才是我们设置的100px。

接下来我们来看另一个例子:

<style>
        *{
            margin: 0;
            padding: 0;
        }
        div{
            width: 100px;
            height: 100px;
            border: 1px solid red;
            padding: 10px 20px;
        }
        span{
            width: 100px;
            height: 100px;
            background-color: green;
        }
    </style>
</head>
<body>
    <div>123</div>
    <span>11</span><span>222</span>
</body>

image.png

页面呈现的是这个效果,诶为什么我们给span设置了宽高它还只是这么一点呢,这是因为行内元素不能被设置宽高,它们是根据文本流来排列的,只会占据必要的空间。 如果想要改变,我们可以改变它的display,行内元素默认值为inline,我们将它设置为display:block

image.png

就作为块级元素显示了,并且可以设置宽高,同样我们可以将div也作为行内元素显示:display:inline

image.png

还有display:nline-block它可以让元素像行内元素一样显示,并且可以设置高度:

image.png

BFC

BFC(Block Formatting Context,块级格式化上下文),是web页面中盒模型布局的一种CSS渲染模式,它是一个独立的渲染区域,在内部的html元素按照一定的规矩进行布局,内部的元素不会受到外部元素的影响。接下来我们慢慢学习它的特性:

  1. 垂直排列:内部的Box(块级元素)会在垂直方向上一个接一个地放置,即每个块级元素独占一行。
  2. 外边距折叠:属于同一个BFC的两个相邻Box的margin会发生叠加,这种现象称为“margin塌陷”。
style>
        * {
            margin: 0;
            padding: 0;
        }
        .box {
            width: 200px;
            height: 200px;
            background-color: lightblue;
            border: 1px solid black;
        }
        .box1{
            margin-bottom: 50px;
        }
        .box2{
            margin-top: 30px;
        }
    </style>
</head>
<body>
    <div class="box box1">Box1</div>
     <div class="box box2">Box2</div>
</body>

image.png

可以看到我们为box1设置了margin:50px,为box2设置了margin:30px,按道理来说它们的间距应该是80px,但是并没有,就如同规则所说一样,margin会进行重叠,最终的间距值取决于margin大的那一方。我们可以通过为box2增添一个父容器并设置其属性为overflow:hidden来创建一个新的BFC。这样就可以解决高度塌陷的问题。

    <div style="overflow: auto;">
        <div class="box box2">Box2</div>
    </div>

image.png

  1. 不与浮动元素重叠:BFC的区域不会与float box重叠。这意味着如果一个元素形成了一个新的BFC,那么它将不会被浮动元素覆盖。
  <style>
  .container {
    border: 2px solid black;
    padding: 10px;
  }

  .float-box {
      float: left;
      width: 150px;
      height: 100px;
      background-color: lightblue;
      margin: 10px;
  }

  .bfc-box {
      width: 300px;
      height: 100px;
      background-color: lightgreen;
      /* overflow: auto; 创建 BFC */
  }
  </style>
</head>
<body>
  <div class="container">
    <div class="float-box">这是一个左浮动的盒子</div>
    <div class="bfc-box">这是一个创建了 BFC 的盒子</div>
</div>
</body>

image.png

当我们为container增加一个overflow:auto创建BFC后:

image.png

  1. 包含浮动:计算BFC的高度时,浮动元素也参与计算。这可以用来解决父元素因为浮动子元素而高度坍塌的问题。
  <style>
  /* 而用 BFC 清除浮动的原理就是:计算 BFC 的高度时,浮动元素也参与计算。只要触发父元素的 BFC 即可。 */
  .parent {
    background-color: red;
    /* overflow: hidden; */
  }
  .child {
    float: left;
    height: 200px;
    width: 200px;
    background-color: green;
  }
  </style>
</head>
<body>
  <div class="parent">
    <div class="child"></div>
  </div>
</body>

image.png

可以看到此时,parent元素高度为0,当我们为他加上overflow:hidden创建一个BFC后:

image.png 5. 隔离性:BFC就是页面上的一个独立容器,容器里面的子元素不会影响外面的元素,也不会受到外部元素的影响。

<style>
  .container {
    border: 2px solid black;
    padding: 10px;
}

.float-box {
    float: left;
    width: 150px;
    height: 100px;
    background-color: lightblue;
    margin: 10px;
}

.bfc-box {
    width: 300px;
    height: auto;
    background-color: lightgreen;
    /* overflow: auto; 创建 BFC  切换 */
    padding: 10px;
    border: 1px solid #ccc;
}
  </style>
</head>
<body>
  <div class="container">
    <div class="float-box">这是一个左浮动的盒子</div>
    <div class="bfc-box">
        <p>这是创建了 BFC 的盒子内部的内容。</p>
        <p>注意,这个内容不会被外部的浮动元素影响。</p>
    </div>
  </div>

image.png

在我们未创建BFC时,bfc-box中的元素受到浮动元素的影响导致文字环绕着浮动元素,但是为它创建一个BFC后:

image.png 7. 左对齐:每个元素的margin box的左边,与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。

    <style>
        *{
            margin: 0;
            padding: 0;
        }
        .container{
            border: 2px solid black;
            padding: 10px;
            /* 父元素的不影响子元素的布局 */
            /* overflow: hidden; */
        }
        .float-left{
            /* 启动了一个新的FFC */
            float: left; 
            width: 150px;
            height: 100px;
            background-color: lightblue;
            margin: 10px;
        }
       .margin-box{
            width: 200px;
            height: 100px;
            background-color: lightgreen;
            margin: 20px 0 20px 50px;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="float-left">这是一个左浮动的元素</div>
        <div class="margin-box">这是有左侧外边距的盒子这是有左侧外边距的盒子这是有左侧外边距的盒子</div>
    </div>

image.png

形成BFC的条件

1. 根元素(HTML)

  • 条件:HTML 文档的根元素(<html>)总是会形成一个新的 BFC。
  • 解释:根元素是页面的最外层容器,它自然会创建一个独立的渲染区域。

2. 浮动元素(float 不为 none

  • 条件:当一个元素的 float 属性设置为 left 或 right 时,它会形成一个新的 BFC。
  • 解释:浮动元素从普通流中部分脱离出来,为了确保浮动元素不会影响其他非浮动元素的布局,浏览器会为浮动元素创建一个新的 BFC。

3. 绝对定位或固定定位元素(position 为 absolute 或 fixed

  • 条件:当一个元素的 position 属性设置为 absolute 或 fixed 时,它会形成一个新的 BFC。
  • 解释:绝对定位和固定定位的元素从普通流中完全脱离出来,它们不再受父元素的影响,因此需要创建一个新的 BFC 来管理它们的布局。

4. display 为某些特定值

  • 条件:当一个元素的 display 属性设置为以下值时,它会形成一个新的 BFC:

    • inline-block
    • table-cell
    • table-caption
    • flex
    • inline-flex
    • grid
    • inline-grid
    • flow-root(CSS 新增的值,专门用于创建 BFC)
  • 解释:这些 display 值会改变元素的默认布局行为,创建一个新的 BFC 来管理其内部内容的布局。

5. overflow 不为 visible

  • 条件:当一个元素的 overflow 属性设置为 hiddenauto 或 scroll 时,它会形成一个新的 BFC。
  • 解释:通过设置 overflow,浏览器会创建一个新的 BFC 来确保容器能够正确包裹其内部的浮动元素或溢出的内容,防止高度坍塌等问题。

6. contain 属性

  • 条件:当一个元素的 contain 属性设置为 layoutcontent 或 paint 时,它会形成一个新的 BFC。
  • 解释contain 属性用于优化布局、样式和绘制,帮助浏览器更高效地处理复杂的页面结构。contain: layout 会创建一个新的 BFC,确保该元素的布局不会受到外部元素的影响。

7. 多列布局(column-count 或 column-width

  • 条件:当一个元素使用了多列布局(column-count 或 column-width)时,它会形成一个新的 BFC。
  • 解释:多列布局会将内容分成多个列,为了确保每一列的内容不会相互干扰,浏览器会为多列容器创建一个新的 BFC。

8. writing-mode 为 vertical-rl

  • 条件:当一个元素的 writing-mode 属性设置为 vertical-rl 时,它会形成一个新的 BFC。
  • 解释writing-mode 用于控制文本的书写方向,vertical-rl 表示从右到左的垂直书写模式。为了适应这种特殊的书写方式,浏览器会为该元素创建一个新的 BFC。

9. will-change 属性

  • 条件:当一个元素的 will-change 属性指定了可能会发生变化的属性时,浏览器可能会为该元素创建一个新的 BFC,以优化性能。
  • 解释will-change 提示浏览器提前为某些属性的变化做好准备,虽然它不一定总是创建 BFC,但在某些情况下确实会触发 BFC 的创建。

10. transform 或 filter 属性

  • 条件:当一个元素应用了 transform 或 filter 属性时,浏览器可能会为该元素创建一个新的 BFC,以确保其渲染效果不会影响其他元素。
  • 解释transform 和 filter 会创建一个新的堆叠上下文(stacking context),并且在某些情况下也会触发 BFC 的创建。

总结

形成 BFC 的条件多种多样,主要包括浮动、绝对定位、特定的 display 值、overflow 设置等。理解这些条件可以帮助开发者更好地控制页面布局,避免常见的布局问题,如浮动元素导致的高度坍塌、外边距折叠等。通过合理使用 BFC,可以创建更加稳定和可控的布局结构。

常见应用场景

  1. 清除浮动:通过设置 overflow: hidden;display: flow-root;,可以创建一个新的 BFC,从而确保父容器能够正确包裹浮动的子元素,防止高度坍塌。
  2. 防止外边距折叠:通过创建 BFC,可以阻止相邻块级元素之间的垂直外边距发生折叠,确保布局的稳定性。
  3. 隔离浮动的影响:通过创建 BFC,可以确保某个容器内的浮动元素不会影响外部的非浮动元素,也不会被外部的浮动元素影响。
  4. 创建独立的布局区域:通过创建 BFC,可以将某些部分的布局与其他部分隔离开来,使得布局更加模块化和易于管理。
❌
❌