碎碎念
上一篇讨论浮动与清除浮动的博客中,最后提到了BFC(Block Formatting Contexts)的概念。
我建议每个学前端的人都要把BFC理解透彻,这样在解决外边距堆叠,高度塌陷及各种定位、布局带来的负面影响时,都能了解原理,选择恰当的解决办法。
废话不多说了,开始:P
官方文档对BFC的解释
首先,我们来看看官方文档是如何描述BFC的,我把这段定义拆成三小段,分段描述:
Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.
- 浮动,绝对定位,不是块级盒的块级包含块(例如inline-block,table-cells和table-caption),及overflow值不为visible的块级盒子为他们的内容新的块级格式化上下文(BFC)
In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block. The vertical distance between two sibling boxes is determined by the 'margin' properties. Vertical margins between adjacent block-level boxes in a block formatting context collapse.
- 在一个块级格式化上下文中,盒子是从包含块顶部开始,一个接一个的垂直排列。
- 两个后代盒子的垂直距离由margin即外边距属性决定。
- 在一个块级格式化上下文中,两个相邻的块级盒子外边距会折叠;
In a block formatting context, each box's left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch). This is true even in the presence of floats (although a box's line boxes may shrink due to the floats), unless the box establishes a new block formatting context (in which case the box itself may become narrower due to the floats).
- 在一个块级格式化上下文中,每个盒子的外边距和其包含块的左边沿相接触(对于从右向左的格式则相反);
- 即使在有浮动元素的存在,情况下也是如此(一个盒子的行盒会因为浮动而收缩),除非这个盒子建立了一个新的BFC(在某些情况下,这个盒子自身会变窄)
BFC的理解
- BFC就是对B(Block)的FC(Formatting Contexts),简单说就是块级元素的排列规则,同样的还有IFC,即对行内元素的排列规则。
- Formatting Contexts,是W3C CSS2.1引入的概念,可以理解为页面中的一块渲染区域,并且与外界相隔离,有一套自己的规则,它决定了在这块区域中其子元素ru和定位吗,排列以及和其他元素的关系和相互作用。
- CSS2.1中增加了BFC和IFC,CSS3中还增加了GFC和FFC。
- Box是CSS布局的基本单位,也就是说,一个页面实际上是由很多Box组合而成的。对Box声明不同的display类型,则生成不同类型的Box。不同类型的Box会参与不同的Formatting Contexts(一个决定如何渲染文档额的容器),因此Box内的元素会以不同的方式渲染。
BFC的特性
一个元素,声明了某种规则(后面会讲触发规则),触发了BFC后,便拥有了BFC特性,那什么是BFC特性呢?特性就是前一段所说的,其为拥有一套独立的渲染规则的区域,并且这块区域不受外界的影响,是相对隔离的区域(也有的地方说容器)。区域中的子元素不会在布局上影响外面的元素,反之亦然。同时,BFC仍然属于文档中的普通流。
- 内部的box会在垂直方向上一个接一个的排列;
- Box垂直方向上的距离由外边距决定。当两个相邻的容器在同一个BFC中时,他们的垂直方向会发生外边距叠加,换句话说,只要把两个元素分隔在不同的BFC,便可以消除影响,从而解决外边距合并问题;;
- 每个元素的左外边距与包含块的左边界相接触(从左到右),即使浮动元素也是如此。(这说明BFC中的子元素不会超出它的包含块,而position为absolute的元素可以超出它的包含块边界);
- BFC的区域不会与float box所占的区域重叠;
- 计算BFC的高度时,浮动子元素也参与计算;(顺带达到了撑开父容器,清除浮动的目的)
如何触发BFC
只要父容器上声明以下任一属性即可触发 BFC:
- float 除了none以外的值
- overflow除了visible以外的值(hidden,auto,scroll )
- display (table-cell,table-caption,inline-block,flex,inline-flex)
- position(absolute,fixed)
- fieldset元素(实验性质)
- 根元素
以上这些规则,均可以触发BFC,具体的选用要取决于场景,不同的属性会带来不同的作用效果;
BFC的应用
- 解决外边距叠加,方法:使父容器添加触发BFC的元素;
- 清除浮动:方法:利用计算BFC高度时,浮动元素也会参与计算的原理,所以为了闭合浮动,我们要对父容器触发BFC;
- 用于布局:利用BFC不会与float box重叠的原理及元素的左/右外边距会触碰到包含块的边沿原理,创建两栏/三栏布局(左右浮动且定宽,中间创建BFC);
父容器使用overfolow: auto | hidden撑开高度的原理
初次看到overflow:hidden可以解决外边距叠加,清除浮动时,我是很困惑其原理的。直到后面,我尝试理解了BFC,知道其会触发BFC特性,生成一个新的渲染区域,有自己的规则,与外界隔离,也就是不受其他BFC影响了。
但回过头想,我们看下MDN对overflow属的描述:
The overflow CSS property is shorthand for the overflow-x and overflow-y properties, and specifies what to do when content is too large to fit in its block formatting context.
也就是说,overflow属性是用来处理当内容过于长以至于溢出块级容器时,CSS对文本的处理方式;overflow: hidden则是溢出的内容会被裁剪,且不可见。
可以这样理解,overflow:hidden是为了触发包含块计算内容高度,不计算高度overflow怎么裁剪多余部分并隐藏呢?
那怎么计算高度呢?声明了overflow:hidden后需要根据内容的高度来裁剪,浮动元素脱离了文档流,如果未申明高度或高度为auto,那么overflow的高度计算就无从算起,所以要将浮动元素的高度也计算在内,overflow才会起作用,由此,顺带达成了清除浮动的目标;
总结
很多人第一次接触BFC时经常有一个疑问,BFC概念太多了,资料越多往往更难理解。其实,对于BFC我们只需要知道使用一定的CSS声明可以触发BFC,浏览器对生成的BFC有一系列的渲染规则,利用这些渲染规则我们可以达到一定的布局效果,为了达到特定的布局效果我们让元素生成BFC。
我们要记住BFC是页面元素里一个独立存在作用块,它不影响它外面的布局,外面的元素也不会影响到BFC里面的布局,有时候对于页面一些异常效果我们往BFC的思路想想可能会得到解决。