从头开始复习css之BFC

724 阅读7分钟

夏天快到了,又到了白大腿横飞的时代。坐下来摸了摸腰间残留的今年五花肉就突然觉得时光待我并不怎么宽厚啊。

昨天写了一篇关于浮动的文章,里面就提到了BFC 并介绍了几种利用BFC来清除浮动的方式,那么今天来解答一下:到底什么是BFC?

一、 什么是BFC?

其实你叫我单纯的回答你们什么是BFC,我只能告诉你BFC的全称(Block Fromatting Context)和中文翻译名(块级格式化上下文)。如果你叫我深入的解释这这个名词,这就好比你叫我来解释什么叫男生/女生一样,大家我都知道这两个名词,但是你叫人跟你解释清楚却是很麻烦,同样bfc也是如此。

1.1、 w3c对BFC的解释

首先我们来看看W3C对BFC的解释

w3c
我在这里简单的翻译一下:(可能不怎么标准呀)

浮动元素、绝对定位元素等非快级盒子的快级容器(例如:inline-blocks, table-cells, 和 table-captions),以及overflow属性不为visiable的块级元素元素,都会其内容建立新的块级格式化上下文。

在BFC(块级格式化上下文)中,盒在垂直方向一个一个的放置,从包含块的顶部开始,相邻的兄弟盒子之间的垂直距离由margin属性来决定,在同一个BFC(块级格式化上下文)中的相邻兄弟之间的margin会被合并。

在一个BFC(块级格式化上下文)中,最左边的左边距和包含块的左边相同(对于从右向左格式的结构,内外也是挨着的)。即使存在浮动情况(尽管盒子的大小可能因为内部子盒子的浮动而变窄),这也成立,除非子盒子内建立了一个新的BFC(块级格式化上下文),这种情况下,该盒自身可能因为浮动变窄。

讲道理,不知道是不是我翻译的缘故,我硬是没看懂orz! 算了我们还是来看一下中文版MDN对BFC的解释吧:

1.2、 w3c对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)。 块格式化上下文包含创建它的元素内部的所有内容.

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

二、用代码来解释上面懵懂的话语吧

其实上面找了这么多文档,其实大抵还是不怎么懂的,但是我们就来按照他们的说法来写点点代码,来看下面一段代码:

// html
<div class="parent">
  <div class="son"></div>
</div>
// css
*{
  margin: 0;
  padding: 0;
}
.parent {
  width: 200px;
  border: 10px solid pink;
  margin:100px;
}
.son {
  width: 100px;
  height: 100px;
  background: red;
  float: left;
}

效果如下:

效果
这里我们发现由于子元素添加了浮动属性,导致父元素的宽度并没有被撑开。那我们按照文档的说法,来做一下简单的实验:

.parent {
  width: 200px;
  border: 10px solid pink;
  margin:100px;
  /*overflow: hidden;*/
  /*display: inline-block;*/
  /*display: flex;*/
  /*display: flow-root;*/
  /*position: absolute;*/                      
  ...
}

这里我们发现了一个情况:即使是子元素添加了浮动属性,父元素都会被子元素撑开。这里我们就差不多能明白前面W3C的第一段话,使用上面一系列的属性能让父盒子产生BFC,我在这里总结一下BFC的功能,就是让父盒子包裹起子盒子来,也就可以达到清除浮动的功能。

然后我们在代码的基础上增加一个儿子来继续探究BFC的作用:

// html
<div class="parent">
  <div class="son"></div>
  <div class="son1"></div>
</div>
// css
.son {
  width: 100px;
  height: 100px;
  background: red;
  float: left;
}
.son1 {
  width: 100px;
  height: 100px;
  background: blue;
  display: flow-root;
}

首先在son1中不添加display属性的时候效果如下:

效果
此时我们发现由于son盒子是浮动的不占据位置,此时son1就会霸占son在父盒子的位置产生上面覆盖的效果。 然后我们加入display属性的时候效果如下:
效果
由上面的对比效果我们可以明显的发现:每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。并且相邻BFC盒子不会重叠

这里有这么个东西值得大家注意的,如果我在son1盒子上面增加一个margin-left的属性,我们发现并没有效果,直到margin-left的长度大于son盒子的时候才会产生偏移。

效果
但是如果在son上面加一个margin-right的属性:
效果

从上面这两个例子能更清楚的说明相邻BFC盒子不会重叠的特性。

紧接着我们来继续的探究一下垂直margin合并的问题,修改一下上面的代码:

.son {
  width: 100px;
  height: 100px;
  background: red;
  margin: 20px;
}
.son1 {
  width: 200px;
  height: 100px;
  background: blue;
  margin: 20px;
}

效果
从面的效果可以发现我们就可以很清楚的可以发现:盒子垂直方向的距离由margin决定。属于同一个BFC的两个相邻子盒子的margin会发生重叠

如果想清除这种重叠效果,可以在son1的外层套一个盒子(穿上一件马甲),就像这样:

效果

三、 重新梳理浮动的作用:

1、 自适应两栏布局 2、 清除内部浮动 3、 防止垂直 margin 重叠 总而言之:BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此

说在最后

今天在最后想说一下关于使用BFC特性的问题。我们都知道CSS有一个不正交的特别。通常来说:一个属性并不是因为单独某个效果而设计的,可能某个属性会有各种不同的效果。怎么理解?例如:overflow:hidden属性,他不单单只是产生了BFC的效果,他还有一些额外的作用:当子盒子的长/宽大于父盒子的时候,就会将溢出的子元素内容给隐藏掉。如果我们单单只想要BFC特性的话,要选用适合场景的属性。

可能官方看到我们这些底层程序员的呼声,推出了display:flow-root属性,这个是专门用来生成BFC的,但由于这个属性比较新,很多浏览器都不能完美的支持,使用的适合也要谨慎小心。

说了这么多,只是想让诸位看官在开发里面要大胆使用,仔细验证,在项目条件支持的角度下 多去使用新的知识,毕竟时代是在不断进步的,我们也要不断更新自己的知识储备。好了,也已经过了12点了,睡觉去了。