今天看啥  ›  专栏  ›  YyzclYang

BFC 初体验

YyzclYang  · 掘金  ·  · 2018-08-13 06:12
阅读 20

BFC 初体验

1 引言

BFC(Block Formatting Context),中文翻译为“块格式化上下文”。它有一个明显的特性,那就是如果一个元素拥有了 BFC 特性,那么它内部元素不受外部元素的影响,外部元素也不会受其内部元素的影响。

但到底什么才是 BFC 呢?

先来看看 MDN 对 BFC 的解释。

2 MDN 对 BFC 的解释

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

下列方式会创建块格式化上下文:

  • 根元素或包含根元素的元素
  • 浮动元素(元素的 float 不是 none)
  • 绝对定位元素(元素的 position 为 absolute 或 fixed)
  • 行内块元素(元素的 display 为 inline-block)
  • 表格单元格(元素的 display为 table-cell,HTML表格单元格默认为该值)
  • 表格标题(元素的 display 为 table-caption,HTML表格标题默认为该值)
  • 匿名表格单元格元素(元素的 display为 table、table-row、 table-row-group、table-header-group、table-footer-group(分别是HTML table、row、tbody、thead、tfoot的默认属性)或 inline-table)
  • overflow 值不为 visible 的块元素
  • display 值为 flow-root 的元素
  • contain 值为 layout、content或 strict 的元素
  • 弹性元素(display为 flex 或 inline-flex元素的直接子元素)
  • 网格元素(display为 grid 或 inline-grid 元素的直接子元素)
  • 多列容器(元素的 column-count 或 column-width 不为 auto,包括 column-count 为 1)
  • column-span 为 all 的元素始终会创建一个新的BFC,即使该元素没有包裹在一个多列容器中(标准变更,Chrome bug)。

创建了块格式化上下文的元素中的所有内容都会被包含到该BFC中。

块格式化上下文对浮动定位(参见 float)与清除浮动(参见 clear)都很重要。浮动定位和清除浮动时只会应用于同一个BFC内的元素。浮动不会影响其它BFC中元素的布局,而清除浮动只能清除同一BFC中在它前面的元素的浮动。外边距折叠(Margin collapsing)也只会发生在属于同一BFC的块级元素之间。

感觉怎么样?反正我读下来的感觉就是:

好像也没具体的说什么是 BFC 。

3 BFC 的个人理解

个人感觉 BFC 就像女孩子的好感一样,没法说清楚什么才算是女孩子对你有好感,但是一旦女孩子对你有好感,你就知道了。

BFC 同理,没法说清楚什么是 BFC ,但是当 BFC 一出现,你就知道那个东西属不属于 BFC ,也就是拥有某些特定属性的东西就是 BFC ,能触发 BFC 的属性 MDN 上都有说明。

4 BFC 的用处

4.1 管住子元素

BFC 元素里面元素不能影响外面的元素,利用这个特性,可以用来管住子元素。

4.1.1 浮动元素

我们知道,当一个元素变成浮动元素后,那么它就会脱离文档流,对页面布局产生影响,利用 BFC 就可牢牢管住浮动元素,消除这种影响,

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>BFC</title>
</head>

<body>
  <div class="father">
    <div class="child"></div>
  </div>
</body>
<style>
  .father {
    width: 300px;
    border: 1px solid red;
  }

  .child {
    width: 200px;
    height: 100px;
    background: pink;
  }
</style>

</html>
复制代码

从动态图中可以看到,当我们给child元素加一个浮动时,它就会脱离father元素的掌控,如果这时候把father元素变成 BFC (float: left;display: inline-block; 都可以将元素变成 BFC 元素,其他更多方法看 MDN 的解释),那么child元素就会重新被father元素所掌控。

对于清楚浮动,也可以利用clearfix来实现,这个更推荐clearfix,因为 BFC 有副作用,除了display: flow-root之外,其他将元素变成 BFC 的都是给元素加了一个其他的属性,这就会造成副作用。

display: flow-root是一个专门生成 BFC 的一个属性,但是它是一个高级属性,浏览器支持不全面。

4.1.2 margin

当我们给子元素一个margin时,它的margin部分会跑到父级元素外面去。

当给子元素加一个margin-top: 100px;后,会发现子元素比父元素大了,这个时候把父级元素变成 BFC 后,父级元素又会重新把子元素包进来。

4.2 和兄弟划清界限

BFC 元素外面的元素不能影响其里面的元素,利用这个特性可以和兄弟元素划清界限,不受兄弟元素的影响。

4.2.1 清除外边距叠加

我们知道,在CSS当中,相邻的两个盒子(可能是兄弟关系也可能是祖先关系)的外边距可以结合成一个单独的外边距。这种合并外边距的方式被称为折叠,并且因而所结合成的外边距称为折叠外边距。

而当其中一个元素变成了 BFC 之后,里面的子元素就不会与这个元素的相邻元素发生外边距叠加。

来看例子。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>BFC</title>
</head>
<body>
  <div class="child"></div>
  <div class="father">
    <div class="child"></div>
  </div>
  <div class="child"></div>
</body>
<style>
  .father{
    
  }
  .child{
    width: 200px;
    height: 100px;
    background: pink;
    margin: 20px;
  }
</style>
</html>
复制代码

这时候会发生外边距叠加,它们中间的边距为20px。如果存在 BFC ,就会与旁边的元素划清界限,也就不会发生外边距叠加了。

从代码及动态图可以看到,其实是father元素里面的child元素与father元素的兄弟元素发生了外边距叠加,当father元素变成 BFC 后,里面的child元素与father元素的兄弟消除了外边距叠加。

我们来看另外一种情况,看下面的动态图。

从图中可以看到,BFC 元素本身不会与其兄弟元素消除外边距叠加,它只能消除其子元素与 BFC 兄弟元素之间的外边距叠加。

4.2.2 打破兄弟浮动元素的压迫

我们知道当兄弟元素变成浮动元素后,它就会“骑”在我们身上,这我们肯定不能忍啊。那咋办呢?把我们自己变成 BFC 就好了。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>BFC</title>
</head>
<body>
<div class="father">
  <div class="child1"></div>
  <div class="child2"></div>
</div>
</body>
<style>
  .father{
    width: 350px;
    background: #999;
  }
  .child1{
    float: left;
    width: 100px;
    height: 200px;
    background: pink;
  }
  .child2{
    display: flow-root;
    width: 200px;
    height: 300px;
    background: red;
  }
</style>
</html>
复制代码

那我想离这个想压迫我的兄弟远点那怎么办?我们自然而然地想到了margin-left,来试试margin-left: 20px;,来看看效果。

咦?咋没用呢?来看看它的margin

原来兄弟元素虽然不能压迫我们自身,但它仍旧可以“骑”在我们的外边距上。正所谓 BFC 的一个特性:外部元素不能影响 BFC 内部元素,但没说外部元素不能影响 BFC 元素本身。

既然这样,那就加大力度,我来个margin-left: 120px

这下倒是与兄弟元素分开了,但有一个很大的缺点,当兄弟元素的宽度发生变化时,它们之间的间距也发生了变化,如果想要其间距固定怎么办?

我们换个思路,把margin写在浮动元素上怎样?

从动态图中可以看到,当margin写在浮动元素上后,不管其宽度怎么变,与兄弟 BFC 元素总会有着固定的间隔。

利用这个特性,我们能完成一个多栏的布局。

文章中如有错误之处,忘不吝赐教。

参考资料:




原文地址:访问原文地址
快照地址: 访问文章快照