面试中经常遇见BFC相关问题,经常问什么情况下会触发BFC,网络博客中也有很多文章提及BFC,至少我看过后,浏览器是如何在正常流下排版元素的,而BFC和IFC在排版元素的时候又是扮演什么角色这部分内容都是没有介绍的。所以搞懂BFC和IFC必须的从浏览器排版前的基础概念讲起。
什么是标签、元素、盒
关于标签、元素、盒的的概念,基本上对应着html文本、生成DOM和CSSOM、layout。文本阶段我们把每个闭合或自闭合元素(token)称为标签,通过文本解析(Parse)后生成DOM树一个个的节点称为元素(DOM元素)、之后通过解析后CSSRule(这个过程往往是流式处理的字符流-token流-生成元素及css匹配计算),匹配到对应的元素节点上,计算排版得到元素所占据的大小位置,也就是所谓的盒。
至少目前,我们应该知道盒是浏览器排版元素基本单位。
浏览器产生盒的过程
在css标准中有 block-level elements 和 inline-level elements 两个就是我们所说块级元素和行内元素。
在正常流排版中每个块级元素独占一行、逐行排版的, 每个行内元素或文字依次排列,容不下换行依次排列的。
现在,如果站在产生盒的过程,我们把元素的排版大概如下步骤:
- 当遇到块级元素:会产生一个block-level-boxs 块盒, 块盒上下排列。
- 当遇到行内级元素或者文字: 会产生一个inline-boxs 行盒,当容器容不下元素时,会创建新的行盒依次排列新的行内元素。
至少目前盒和元素关系,应该是元素根据自身类型会产生盒,一个块级元素会产生一个块级盒独占一行,而多个行内元素至少会产生一个或多个行盒,多个行盒依次上下排列。一段文本会产生一个或多个行盒。
- block-level-boxs
- inline-boxs
关于盒模型
有了盒,不得不说下一个我们很熟悉的概念盒模型 块级盒模型如下如:
行模型如下图:
至少盒模型包括元素margin、padding、border、content的内容
而行模型涉及行的line-height、top、bottom、middle、text-top、text-bottom、base-line相关概念,也对应css vertical-align相关属性值。
再谈BFC和IFC
- 我们知道了标签、元素、盒的概念和关系。
- 我们知道了元素产生盒的过程。
接下浏览器选择相应盒模型,计算得出盒所占据位置大小、盒与盒之间的留白等信息。 然而不管BFC还是IFC都有一个contex当前所依赖状态,而这个状态根据元素有子元素和父元素的关系, 而元素又会产生盒的关系, 所谓Context应该就是当前排版盒所依赖父级盒block-container。
盒在排版时有其依赖上下文环境父级盒,而其内部或者元素内部又可以产生新的盒,根据盒模型对这些新的盒进行排版,从而产生新的上下文环境就是所谓BFC和IFC了。
而当前BFC和IFC依赖上下文环境, 父级盒则称为block-containers。站在元素角度就是,一个元素内部可以继续按照正常流排版,这个元素所产生的盒为block-containers。
最后是触发BFC还是BFC上文合并,一锤定音了。
讲清楚之前,我们还是看具体例子来做演示,来看看所谓触发BFC例子,如下图: 从上图,每个元素的上下间距为20px, 这也侧面margin设计的时候被当做了元素间留白,元素间margin不会被叠加。
上下文合并的栗子
去除父级display hidden 属性值之后, 子元素留白空间跟父级别元素留白发生合并,也就是父元素所在BFC和子元素所在BFC发生合并。
我们看文档定义: 总结一下文档意思:盒内不会创建新的格式化上下文的情况只有一种,自身为Block conatiner盒 且是为block box的盒,加上元素overflow属性为visible时候,盒内不会有新的格式化上下文环境产生。 大白话:块级元素overflow为visible时候盒父级格式化上下文环境发生合并, 子元素margin和父级元素margin发生折叠(这里我们把文档定义反过来解释,就容易理解多了。)。
上下文合并与float栗子
至此我们BFC就讲完了, 总结一下涉及的概念
- 标签、元素、盒
- 盒模型、行模型
- BFC、IFC
- block-level boxs inline-level boxs block-level element inline-level element
- block-box、block-container