本文由 简悦 SimpRead 转码, 原文地址 juejin.cn
对于 BFC 的概念以及应用场景一直都不是很明白,今天着重去了解了一下,做了以下总结。
前言
对于 BFC 的概念以及应用场景一直都不是很明白,今天着重去了解了一下,做了以下总结。
BFC 的定义
在解释 BFC 是什么之前,需要先介绍 Box、Formatting Context 的概念。
Box: CSS 布局的基本单位
Box 是 CSS 布局的对象和基本单位, 直观点来说,就是一个页面是由很多个 Box 组成的。元素的类型和 display 属性,决定了这个 Box 的类型。 不同类型的 Box, 会参与不同的 Formatting Context(一个决定如何渲染文档的容器),因此 Box 内的元素会以不同的方式渲染。让我们看看有哪些盒子: block-level box:display 属性为 block, list-item, table 的元素,会生成 block-level box。并且参与 block fomatting context; inline-level box:display 属性为 inline, inline-block, inline-table 的元素,会生成 inline-level box。并且参与 inline formatting context; run-in box: css3 中才有, 这儿先不讲了。
Formatting context
Formatting context 是 W3C CSS2.1 规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。最常见的 Formatting context 有 Block fomatting context (简称 BFC) 和 Inline formatting context (简称 IFC)。 CSS2.1 中只有 BFC 和 IFC, CSS3 中还增加了 GFC 和 FFC。
BFC
BFC(Block Formatting Context)直译为 “块级格式化范围”。是 W3C CSS 2.1 规范中的一个概念,它决定了元素如何对其内容进行定位,以及与其他元素的关系和相互作用 当涉及到可视化布局的时候,Block Formatting Context 提供了一个环境,HTML 元素在这个环境中按照一定规则进行布局。一个环境中的元素不会影响到其它环境中的布局。比如浮动元素会形成 BFC,浮动元素内部子元素的主要受该浮动元素影响,两个浮动元素之间是互不影响的。这里有点类似一个 BFC 就是一个独立的行政单位的意思。 也可以说 BFC 就是一个作用范围。可以把它理解成是一个独立的容器,并且这个容器的里 box 的布局,与这个容器外的毫不相干
怎样才能形成 BFC
- float 的值不能为 none
- overflow 的值不能为 visible
- display 的值为 table-cell, table-caption, inline-block 中的任何一个
- position 的值不为 relative 和 static
BFC 的约束规则
- 内部的 Box 会在垂直方向上一个接一个的放置
- 垂直方向的距离有 margin 决定 (属于同一个 BFC 的两个相邻 Box 的 margin 会发生重叠,与方向无关)
- 每个元素的 margin box 的左边, 与包含块 border box 的左边相接触 (对于从左往右的格式化,否则相反)。即使存在浮动也是如此
- BFC 的区域不会与 float 的元素区域重叠
- 计算 BFC 的高度时,浮动子元素也参与计算
- BFC 就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面元素,反之亦然
看到以上的几条约束,让我想起学习 css 时的几条规则
Block 元素会扩展到与父元素同宽,所以 block 元素会垂直排列 垂直方向上的两个相邻 DIV 的 margin 会重叠,而水平方向不会 (此规则并不完全正确) 浮动元素会尽量接近往左上方(或右上方) 为父元素设置 overflow:hidden 或浮动父元素,则会包含浮动元素
BFC 的作用
1. 不和浮动元素重叠
如果一个浮动元素后面跟着一个非浮动的元素,那么就会产生一个覆盖的现象,很多自适应的两栏布局就是这么做的。比如下图的效果,参考例子
|
|
案例分析: 很明显,.aside 和. mian 重叠了。试分析一下,由于两个 box 都处在同一个 BFC 中,都是以 BFC 边界为起点,如果两个 box 本身都具备 BFC 的话,会按顺序一个一个排列布局,现在. main 并不具备 BFC,根据 BFC 布局规则第 3 条
每个元素的 margin box 的左边, 与包含块 border box 的左边相接触 (对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
虽然存在浮动的元素 aslide,但 main 的左边依然会与包含块的左边相接触 根据 BFC 布局规则第四条:
BFC 的区域不会与 float box 重叠
我们可以通过通过触发 main 生成 BFC, 来实现自适应两栏布局
|
|
当触发 main 生成 BFC 后,这个新的 BFC 不会与浮动的 aside 重叠。因此会根据包含块的宽度,和 aside 的宽度,自动变窄。效果如下:
2. 清除元素内部浮动
案例代码:
|
|
根据 BFC 布局规则第六条:
计算 BFC 的高度时,浮动元素也参与计算
为达到清除内部浮动,我们可以触发 par 生成 BFC,那么 par 在计算高度时,par 内部的浮动元素 child 也会参与计算。
|
|
加入上面样式,即可解决问题,效果如下:
3. 防止垂直 margin 重叠
|
|
页面如下:
两个 p 之间的距离为 100px,发送了 margin 重叠。根据 BFC 布局规则第二条:
Box 垂直方向的距离由 margin 决定。属于同一个 BFC 的两个相邻 Box 的 margin 会发生重叠
我们可以在 p 外面包裹一层容器,并触发该容器生成一个 BFC。那么两个 P 便不属于同一个 BFC,就不会发生 margin 重叠了。
|
|
效果如下:
按照 BFC 的定义,只有同属于一个 BFC 时,两个元素才有可能发生垂直 Margin 的重叠,这个包括相邻元素,嵌套元素,只要他们之间没有阻挡 (例如边框,非空内容,padding 等) 就会发生 margin 重叠。 因此要解决 margin 重叠问题,只要让它们不在同一个 BFC 就行了,但是对于两个相邻元素来说,意义不大,没有必要给它们加个外壳,但是对于嵌套元素来说就很有必要了,只要把父元素设为 BFC 就可以了。这样子元素的 margin 就不会和父元素的 margin 发生重叠了。
部分内容来自 BFC 背后神奇的原理