[ 面试系列 ] - 六:什么是 BFC?

2,136 阅读5分钟

系列文章

什么是 BFC?

BFC(Block Formatting Context),即块格式化上下文,在前端开发中也是一个老生常谈的问题了,我们首先来看看 MDN 对其的解释:

块格式化上下文(Block Formatting Context,BFC) 是 Web 页面的可视化 CSS 渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。

meme-01

(小声哔哔:听听,这是人说的话吗?)

上翻译机:事实上,BFC 的目的是形成一个相对于外界完全独立的空间,让内部的子元素不会影响到外部的元素。

为什么会出现 BFC?

上面已经解释了什么是 BFC,它的作用是什么,那么为什么会出现 BFC 呢?

相信做过前端开发的同学都遇到过进行页面布局的时候,应该都有遇到过以下情况:

  • 这个元素高度怎么没了?
  • 这两栏布局怎么没法自适应?
  • 这两个元素的间距怎么有点奇怪的样子?
  • ......

为什么会出现上面的情况呢?

究其原因就是因为元素之间相互的影响,导致了预料之外的情况。

那么结合 BFC 的特性,答案就很明了了:BFC 是为了解决元素之间相互影响的问题的。所以 BFC 的功能是形成一个相对于外界独立的空间,让内部的子元素不会影响到外部元素。

怎么创建 BFC?

我们知道了 BFC 是为了解决什么问题而出现的,那么怎么创建一个 BFC 呢?

当然,可以参考 MDN,但这实在是太难记了,通常我们只需要记住下面六种情况即可:

  • float 不为 none
  • position 为 absolute 或 fixed
  • overflow 不为 visible
  • display 为 inline-block 或 table-cell
  • display 为 flex/inline-flex 的直接子元素
  • display 为 grid/inline-grid 的直接子元素

应用场景

父元素高度坍塌

我们知道,如果一个父元素里的子元素一旦设置了浮动,那么父元素就无法检测到子元素的高度,那么如果父元素里的所有子元素都浮动起来的话,父元素的高度就无法被子元素撑开,会塌陷下去,这个现象称为父元素高度塌陷。

我们来看看代码:

<style>
.futher {
  padding10px;
  background-color: deepskyblue;
}

.child {
  width20px;
  height20px;
  background-color: deeppink;
  float: left;
}
</style>
<body>
<div class="futher">
  <div class="child"></div>
</div>
</body>

效果如下:

img-01

显然,这并不是我们希望见到的情况,而通过 BFC 则能很好的解决这个问题:

我们给父元素添加 overflow: hidden,效果如下:

img-02

事实上,既然我们已经知道了父元素为什么塌陷,对于这个问题自然会有其他的解决方案:

比如我们在子元素后面添加一个 div,用于清除浮动:

<style>
.futher {
  padding10px;
  background-color: deepskyblue;
}

.child {
  width20px;
  height20px;
  background-color: deeppink;
  float: left;
}

.clear-both {
  clear: both;
}
</style>
<body>
<div class="futher">
  <div class="child"></div>
  <div class="clear-both"></div>
</div>
</body>

当然,更好的写法可以利用伪元素:

.child::after {
  clear: both;
}

自适应布局

在日常的开发中,两栏自适应布局是非常常见的,通常一遍固定宽度,而另一边则随窗口自适应:

gif-01

对于上图,我们的实现通常是让左侧浮动起来,利用块会自动占满整个宽度的特性,实现右侧自适应。不过如果右侧高度大于了左侧,则会出现如下的尴尬情况:

img-03

这个时候,利用 BFC,也能很好的解决问题:

img-04

同上一个场景,我们知道了出现问题地原因,那么通过别的方案,自然也能解决问题,比如设定一个安全的 margin-left:

:root {
  --safe-margin100px;
}
.left {
  widthvar(--safe-margin);
  height50vh;
  background-color: deeppink;
  float: left;
}
.right {
  margin-leftvar(--safe-margin);
  height100vh;
  background-color: deepskyblue;
}

外边距重叠(边界折叠)

还记得上上集提到的边界折叠吗?

那里主要讲了父元素和子元素的重叠,这里讲一下兄弟之间的重叠。

.one {
  height100px;
  margin-bottom100px;
  background-color: deepskyblue;
}
.two {
  height100px;
  margin-top100px;
  background-color: deeppink;
}

知道边界折叠现象的我们应该清楚,这里两个元素之间的 margin 并不是 (100 + 100 = 200)px,而是取其中的大者(两者一样大)的 100px

img-05

对于这个问题,我们同样可以通过 BFC 来解决:

<style>
* {
  margin0;
  padding0;
}
.one {
  height100px;
  margin-bottom100px;
  background-color: deepskyblue;
}

.twp-wrap {
  overflow: hidden;
}
.two {
  height100px;
  margin-top100px;
  background-color: deeppink;
}
</style>
<body>
<div class="one"></div>
<div class="twp-wrap">
  <div class="two"></div>
</div>
</body>

img-06