深入CSS(4)- BFC | 青训营笔记

147 阅读5分钟

这是我参与「第四届青训营 」笔记创作活动的第7天

「前言」

「什么是 BFC」

bfc:Block Formatting Context,即 块级-格式-上下文

引用W3C的官方解释:

BFC它决定了元素如何对其内容进行定位,以及与其它元素的关系和相互作用,当涉及到可视化布局时,Block Formatting Context提供了一个环境,HTML在这个环境中按照一定的规则进行布局。

是不是听起来一头雾水

要想理解 bfc,首先就要理解什么是 上下文,把它联想为 js 里面的 上下文,换句话说也就是在一个作用域,作用域划分了变量的执行环境,也就是起到 隔离 的作用,同理。那么 bfc 也就是创建一个对于 html 来说的隔离外界的 作用域,在这个作用域中享受着 bfc 提供的规则。

「BFC 布局规则」

bfc 是对具有 block-level box 块级属性 的元素才有的特性(这个块级元素即可以 display: block | list-item | table),可以把 bfc 理解为块级元素可以设置的属性,一旦设置这个 bfc 的属性,就生成响应的规则

  1. 内部的Box会在垂直方向,一个接一个地放置。
  2. Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
  3. 每个元素的margin box的左边,与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
  4. BFC的区域不会与float box重叠。
  5. BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
  6. 计算BFC的高度时,浮动元素也参与计算

「如何触发 BFC 」

就像前文说的一样 bfc 是可以块级元素的一个可以设置的属性,但也不是普通的属性,需要通过其他的方式来触发

  1. 根元素
  2. float属性不为none
  3. position为absolute或fixed
  4. display为inline-block, table-cell, table-caption, flex, inline-flex
  5. overflow不为visible

「实例讲解 BFC」

光说不练假把式,直接上代码

场景:让一张图片和一段文字在一行显示

  <style>
    img,
    p {
      border: 3px solid #000;
    }
  </style>
</head>

<body>
  <div>
    <img src="./图片1.jpg" alt="">
    <p>bfc</p>
  </div>
</body>

基本的样式 image.png

<style>
    img,
    p {
      border: 3px solid #000;
    }

    img {
      float: left;
      margin-left: 20px;
    }
  </style>
</head>

<body>
  <div>
    <img src="./图片1.jpg" alt="">
    <p>bfc</p>
  </div>
</body>

img 浮动,同时设置 margin 为了能更好的看到效果

img 设置了浮动也触发了 bfc

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

image.png 这里就会发现,p 标签的高度和宽度都不是我们想要的,实际效果为 p 标签填充剩余区域的地方,而且高度和图片等高,而且最外层的 div 高度是由 p 控制的,那我们想让他由 pimg 中最高的来控制。

原因:给 img 设置浮动会脱离文档流,所以 div 高度是由 p 控制的。

那怎么解决呢,这时候就要请出 bfc 了,前文说它是块级元素的一个特殊的属性,那我们可以把这个属性添加在一个 上,那块级元素想要添加 bfc 这个属性,其实转换为添加一个 类名,我们使用一个可以触发 bfc 的规则创建

.bfc {
  overflow: hidden;
}

给最外层第 div 添加 bfc

<body>
  <div class="bfc">
    <img src="./图片1.jpg" alt="">
    <p>bfc</p>
  </div>
</body>

image.png

这时候 div 的高度确实是由 pimg 中最高的来控制

原因:给 div 设置了 bfc,相当于给 pimg 划分了一个作用域,自然 div 的高度就被撑开了,利用了 bfc 的布局规则:

计算BFC的高度时,浮动元素也参与计算

但是还有一个问题,p 的长宽还没处理成我们想要的样子

如果给 p 也设置一个 bfc 看看会怎么样

<body>
  <div class="bfc">
    <img src="./图片1.jpg" alt="">
    <p class="bfc">bfc</p>
  </div>
</body>

image.png

为什么给 p 设置一个 bfc就可以解决呢?

原因:给 p 设置 bfc 也是给 p 设置了一块(独立的)作用域,不能延伸到图片的左边去,利用了布局规则:

BFC的区域不会与float box重叠。

最后的代码:

  <style>
    img,
    p {
      border: 3px solid #000;
      background-color: #ccc;
    }

    img {
      float: left;
      margin-left: 20px;
    }

    .bfc {
      overflow: hidden;
    }
  </style>
</head>

<body>
  <div class="bfc">
    <img src="./图片1.jpg" alt="">
    <p class="bfc">bfc</p>
  </div>
</body>

最后总结一下例子:

  • 就如上面的例子,在给 div 设置了 bfc 之后,整个 div 会解决原来 浮动 产生塌陷的状态,原理是 bfc 为了不影响外部元素的布局,而形成了自己独立的绘制区域,所以要计算浮动元素的高度。
  • p 设置 bfc,为了不影响内部的布局,会主动变窄让出原先被覆盖的位置。

「逃离 BFC」

bfc 既然有好处,那也肯定有坏处

解决几个常见的 bfc 的影响


块级元素垂直排列

  <style>
    .box {
      width: 200px;
      height: 200px;
      margin-right: 0;
      border: 3px solid #000;
    }
  </style>
</head>

<body>
  <div class="box"></div>
  <div class="box"></div>
</body>

image.png

即使给每个 box 添加 margin-right也不能使两个 box 在一行排布

原因:根级元素也出发了 bfc

内部的Box会在垂直方向,一个接一个地放置。

解决办法:利用浮动的特性可以解决,或者使两个 box 变为 inline-block


多个 margin 重叠

  <style>
    .box {
      width: 40px;
      height: 40px;
      border: 3px solid #000;
      margin: 40px;
    }

    .container {
      width: 300px;
      height: 300px;
      border: 3px solid #000;
    }
  </style>
</head>

<body>
  <div class="container">
    <div class="box"></div>
    <div class="box"></div>
  </div>
</body>

image.png

两个 box 实际的距离不是两个两倍的 margin

原因:出发了 bfc 的规则:

Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠

解决办法:利用 bfc的规则,使两个 bfc 不相邻,即可以用一个 div 包裹其中的 box

margin-top 传递

对上个例子进行改写

  <style>
    .box {
      margin-top: 40px;
      width: 40px;
      height: 40px;
      border: 3px solid #000;
    }

    .container {

      width: 300px;
      height: 300px;
      background-color: pink;
      /* border: 3px solid #000; */
    }
  </style>
</head>

<body>
  <div class="container">
    <div class="box"></div>
    <div class="box"></div>
  </div>
</body>

image.png

利用 bfc 解决:为 container 添加 bfc,原理利用以下规则

BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。

container 创建一块独立的区域,而不影响外部环境


「参考文章」

BFC神奇背后的原理_w3cschool
CSS 外边距(margin)重叠及防止方法 - 知乎 (zhihu.com), 推荐这篇文章,作者详解讲解关于 margin 重叠的规则

「结语」

通过写这篇文章的同时,发现 CSS 到处都是 bfc,学习bfc的同时,我们可以更好的利用 bfc 解决问题(清除浮动...)