CSS中的BFC和Margin Collapse

Posted by Nutlee on 2016-06-24

众所周知,CSS中的一些知识点都非常琐碎的,这其中关于BFC的部分又是非常基础且非常重要的,下面对BFC从实用角度展开介绍。

什么BFC

Formatting Context:指页面中的一个渲染区域,并且拥有一套渲染规则,他决定了其子元素如何定位,以及与其他元素的相互关系和作用。

BFC:块级格式化上下文,通过CSS属性构造的独立渲染区域,只有Block-level Box参与,该区域拥有一套渲染规则来约束块级盒子的布局,且与区域外部无关。

产生条件

CSS2.1中规定满足下列CSS声明之一的元素便会生成BFC:

  • 根元素
  • float的值不为none
  • overflow的值不为visible
  • display的值为inline-block、table-cell、table-caption
  • position的值为absolute或fixed

另: display:table也认为可以生成BFC,在于table会默认生成一个匿名的table-cell。

约束规则

浏览器对于BFC这块区域的约束规则如下:

  • 生成BFC元素的子元素会一个接一个的放置。垂直方向上他们的起点是一个包含块的顶部,两个相邻子元素之间的垂直距离取决于元素的margin特性。在BFC中相邻的块级元素外边距会折叠。
  • 生成BFC元素的子元素中,每一个子元素做外边距与包含块的左边界相接触,(对于从右到左的格式化,右外边距接触右边界),即使浮动元素也是如此(尽管子元素的内容区域会由于浮动而压缩),除非这个子元素也创建了一个新的BFC(如它自身也是一个浮动元素)。

因此我也可以这么说

  • 内部的Box会在垂直方向上一个接一个的放置。
  • 垂直方向上的距离由margin决定。(完整的说法是:属于同一个BFC的两个相邻Box的margin会发生重叠,与方向无关。)
  • 每个元素的左外边距与包含块的左边界相接触(从左向右),即使浮动元素也是如此。(这说明BFC中子元素不会超出他的包含块,而position为absolute的元素可以超出他的包含块边界)
  • BFC的区域不会与float的元素区域重叠。
  • 计算BFC的高度时,浮动子元素也参与计算,即:可以撑开容器。
  • BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面元素,反之亦然。

什么是Margin Collapse

Margin塌陷、合并、折叠。

即两个相邻盒子的Margin发生合并,两个盒子可能是父子、同辈关系。

产生条件

根据w3c规范,两个margin是邻接的必须满足以下条件:

  • 必须是处于常规文档流(非float和绝对定位)的块级盒子,并且处于同一个BFC当中。
  • 没有线盒,没有空隙(clearance,下面引用的资料里有详细说明。),没有padding和border将他们分隔开。
  • 都属于垂直方向上相邻的外边距,可以是下面任意一种情况:
    • 元素的margin-top与其第一个常规文档流的子元素的margin-top
    • 元素的margin-bottom与其下一个常规文档流的兄弟元素的margin-top
    • height为auto的元素的margin-bottom与其最后一个常规文档流的子元素的margin-bottom
    • 高度为0并且最小高度也为0,不包含常规文档流的子元素,并且自身没有建立新的BFC的元素的margin-top和margin-bottom

形成分析

总体上说是两点,BFC和clearance( 间隙 )。

  • 创建了新的BFC的元素(例如浮动元素或者’overflow’值为’visible’以外的元素)与它的子元素的外边距不会折叠。
  • 浮动元素不与任何元素的外边距产生折叠(包括其父元素和子元素)。
  • 绝对定位元素不与任何元素的外边距产生折叠。
  • inline-block元素不与任何元素的外边距产生折叠。
  • 一个常规文档流元素的margin-bottom与它下一个常规文档流的兄弟元素的margin-top会产生折叠,除非它们之间存在间隙(clearance)。
  • 一个常规文档流元素的margin-top 与其第一个常规文档流的子元素的margin-top产生折叠,条件为父元素不包含 padding 和 border ,子元素不包含 clearance。
  • 一个 ‘height’ 为 ‘auto’ 并且 ‘min-height’ 为 ‘0’的常规文档流元素的 margin-bottom 会与其最后一个常规文档流子元素的 margin-bottom 折叠,条件为父元素不包含 padding 和 border ,子元素的 margin-bottom 不与包含 clearance 的 margin-top 折叠。
  • 一个不包含border-top、border-bottom、padding-top、padding-bottom的常规文档流元素,并且其 ‘height’ 为 0 或 ‘auto’, ‘min-height’ 为 ‘0’,其里面也不包含行盒(line box),其自身的 margin-top 和 margin-bottom 会折叠。

合并结果:

  • 两个相邻的外边距都是正数时,折叠结果是它们两者之间较大的值。
  • 两个相邻的外边距都是负数时,折叠结果是两者绝对值的较大值。
  • 两个外边距一正一负时,折叠结果是两者的相加的和。

解决Margin Collapse

总结

显然,根据BFC相关知识可以解释很多CSS的知识点,如

  • overflow、absolute、float可以用来清除浮动

因此深入了解BFC对HTML+CSS基础非常重要,可以这么说,绝大多数的CSS书写都是按照BFC规则来的,因此构造BFC也是多数情况下CSS书写的 最彻底方案 ,从我个人的经验来说,很多怪异的样式问题尝试构造BFC都能解决,当然学习本身就是一个不停实践不停试错的过程,以下是利用BFC解决的常见问题,不做深入解读。

  • 解决Margin Collapse (Margin合并的元素其一BFC就可解决,不仅限于用这个来解决)
  • 清除浮动
  • 多栏布局

参考资料:
深入理解BFC和Margin Collapse尤其是此文有对 clearance 小间隙的细致说明
我对BFC的理解