前言
在日常开发过程中,经常遇见margin折叠、文本遮挡等的问题,让人很头疼,今天我们就来尝试分析出问题的产生原因。
通过阅读这篇wiki你将了解到:
BFC是什么(解决什么问题)?
什么样的两个元素才是外边距相邻?
什么是视觉格式化模型?
触发BFC的方法?
一、概念
BFC是block formatting context,块级格式化上下文,用于布局块级盒子的一块渲染区域。Formatting context 是 W3C CSS2.1 规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。
在IFC中,盒子水平放置,一个接着一个,从包含块的顶部开始。水平margins,borders,和padding在这些盒子中被平分。这些盒子也许通过不同的方式进行对齐:他们的底部和顶部也许被对齐,或者通过文字的基线进行对齐。矩形区域包含着来自一行的盒子叫做line box。line box的宽度由浮动情况和它的包含块决定。line box的高度由line-height的计算结果决定。一个line box总是足够高对于包含在它内的所有盒子
二、深入探讨
为了让大家更好的理解BFC,先看两个例子:
例子1:

1 | <style> |
上述是两个正常排版的div元素,在浏览器正常的浮动。当左侧div设置了float:left之后界面变成了下图所示。

上图中第二个div浮动到了原来left div所占的位置。但是发现left div占了right div的区域,被迫让right div自动缩进渲染。怎么解决这个问题呢?我们必须让right div的渲染独立出来。这就用到了我们所说的BFC.我们触发了right div的BFC之后(怎么触发我们之后会讲到)如下图:

例子2:

1 | <head> |
实际上inner-box、inner-box2都存在上下边距10px。在直觉来理解蓝色和灰色div中间应该有20px的间距。但是图中却只看到了10px。这就是我们平时所说的margin折叠问题。
强制让inner-box出于另外一个上下文中:
1 | <head> |
此时的渲染结果是:

从上图可以看到篮框和灰框之间margin立刻变成了20px。
例子也看完了,应该对BFC是什么有一些大致的了解了。接下来回顾一写相关概念。
2.1 盒子模型(框模型):
盒子模型是DOM元素的一个基本模型,是浏览器排版和渲染的基本块。在这里不对这个概念进行过多的讲解。

2.2 两个元素外边距相邻的定义:
怎么样的两个盒子模型会产生margin折叠呢?这里引入一个概念就是相邻外边距,这个概念是一个进行过抽象的概念,不是实际直观的那个外边距。下面是一些定义:
双方都是同一个块格式化上下文中的浮动块级框。
双方的框边缘垂直相邻,例如下列一种形式:
没有行框、没有间隙、没有内边距且没有边框隔开它们(注意,某些零高度行框会为此被忽略。)
框的上外边距和其属于正常排版(normal flow)的第一个孩子的上外边距。
框的下外边距和其属于正常排版的下一个兄弟的上外边距。
属于正常排版的最后一个孩子的下外边距和其父亲的下外边距,如果其父亲的高度计算值为„auto‟。
2.3 margin折叠
两个以上的框(可能是兄弟,也可能不是)之间的相邻外边距可以被合并成一个单独的外边距。通过此方式合并的外边距被称为折叠,且产生的已合并的外边距被称为折叠外边距。水平外边距不会合并。
###2.4 视觉格式化模型
containing block(包含块):是视觉格式化模型的一个重要概念,它与框模型类似,也可以理解为一个矩形,而这个矩形的作用是为它里面包含的元素提供一个参考,元素的尺寸和位置往往是由该元素所在的包含块决定的。也就是说一个元素盒子的位置和大小有时是通过相对于一个特定的长方形来计算的,这个长方形就被称之为元素的 containing block。“框的包含块”表示“框所处的包含块”,而不是其产生的包含块。每个框会被给予一个相对于其包含块的位置,但它不会被局限在其包含块内;它有可能会溢出。
并不是每个元素都能为其后辈元素生成一个包含块,所以每一个元素都会根据浏览器视口有一个坐标。
二、触发BFC
1.float:数值不为none的时候。float的w3c文档中描述道:

2.overflow 值不为visible的时候
3.position 不为relative和static
4.display的值为inline-block、table-cell、table-caption
三、解决的问题
2.1 margin 折叠
2.2 文字环绕、防止内容被浮动元素覆盖

这个div元素并没有移动,但是它却出现在浮动元素的下方。div元素的line boxes(指的是文本行)进行了移位。此处line boxes的水平收缩为浮动元素提供了空间。
随着文字的增加,因为line boxes不再需要移位,最终将会环绕在浮动元素的下方,因此出现了那样的情况。这就解释了为什么即使在浮动元素存在时,段落也将紧贴在包含块的左边框上,还有为什么line boxes会缩小以容纳浮动元素。
2.3 包含浮动块
参考文档:
http://www.yangyong.me/css2-bfc%E6%A8%A1%E5%9E%8B%E5%92%8Cifc%E6%A8%A1%E5%9E%8B/
http://www.w3cplus.com/css/understanding-block-formatting-contexts-in-css.html
http://www.zhangxinxu.com/wordpress/2015/02/css-deep-understand-flow-bfc-column-two-auto-layout/