前言
很多前端开发者其实都知道BFC的存在,也都知道BFC存在边距合并的情况,也记得或者背得一些解决办法。但是我相信依然会有很多人是知其然而不知其所以然,BFC是怎么来的,它是个bug吗,IFC又是啥?接下来,让我们一起探讨下BFC的来龙去脉。
排版的由来
大家知道最早涉及到排版的应该是印刷术被发明之后,印刷术使得人们拥有了大批量生产文字作品的能力。人们为了使得印刷时更有规律,空间利用更合理,发明了一种基于格子的排版方式,被内容区域划分为多个小的格子,每个格子填一个内容。直到现代,文字的印刷排版也都是基于格子的。
正常布局流
默认情况下,浏览器按照正常流的方式布局,一般都是从左到右,从上到下。有时候会涉及文字和图片的混合排版,会将文字放在左边,然后紧接着同一行防止图片。这里面就产生了几个概念,
- inline-level-box
行内级别盒,我们叫在同一行内排版的盒子叫做行内级别的盒,如display: inline-table | inline-block或者像img这种替换行的元素会产生inline-level-box。 - block-levelBox
不在同一行内排版的盒子叫做块级别盒子,block-level-box。如display:block 的元素 - line-box
文字和行内级别盒排出来的行我们叫做行盒。
于是整体上来看,我们的页面是有一个个的line-box和多个block-levelBox组成的。line-box也是从上到下排的,但是内部是从左到右排,block-levelBox由于每个都是换一行,所以是从上到下排。我们把从左到右的排班方式用上下文存起来,叫做行内上下文,IFC。把从上往下的布局方式用一个上下文存起来,叫做块级上下文,BFC。所以IFC 其实就是由多个inline-level-box和行内元素(比如文字)构成的,而BFC是由多个line-box和多个block-levelBox构成的。如图
FC
FC的全称是:Formatting Contexts,是W3C CSS2.1规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。FC又分为BFC和IFC和其他(如flex FC)。页面上的所有内容都是格式化上下文的一部分,或者是已定义为以特定方式布局内容的区域。块格式上下文(bfc)将根据块布局规则布局子元素,flex格式上下文将其子元素布局为灵活项等。每个格式上下文都有关于布局在该上下文中的行为的特定规则。
IFC
内联格式上下文存在于其他格式上下文中,可以将其视为段落的上下文。段落创建了一个内联格式上下文,其中在文本中使用诸如<strong>、<a>或<span>元素等内容。
需要注意的是在水平书写模式行中,水平填充、边框和边距将应用于元素,并左右推送文本。但是,不会应用元素上下的边距。将应用垂直填充和边框,但可能会在内容的上方和下方重叠,因为在内联格式上下文中,填充和边框不会将行框推开。参考链接
BFC
BFC(Block Formatting Context )叫做“块级格式化上下文”BFC的布局规则如下:
- 内部的盒子会在垂直方向,一个个地放置;
- 盒子垂直方向的距离由margin决定,属于同一个BFC的两个相邻Box的上下margin会发生重叠;
- 每个元素的左边,与包含的盒子的左边相接触,即使存在浮动也是如此;
- BFC的区域不会与float重叠;
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之也如此;
- 计算BFC的高度时,浮动元素也参与计算。
需要注意的是:不是说块元素就一定会产生一个BFC,这是大多人的误解,比如div、p元素默认情况下是不会创建一个BFC的,他们只是一个block-levelBox。BFC创建是有条件的。
BFC创建规则:
-
根元素(
<html>) -
浮动元素(元素的
float不是none) -
绝对定位元素(元素的
position为absolute或fixed) -
行内块元素(元素的
display为inline-block) -
表格单元格(元素的
display为table-cell,HTML表格单元格默认为该值) -
表格标题(元素的
display为table-caption,HTML表格标题默认为该值) -
匿名表格单元格元素(元素的
display为table、``table-row、table-row-group、``table-header-group、``table-footer-group(分别是HTML table、row、tbody、thead、tfoot 的默认属性)或inline-table) -
overflow值不为visible的块元素 -
display值为flow-root的元素 -
contain值为layout、content或 paint 的元素 -
弹性元素(
display为flex或inline-flex元素的直接子元素) -
网格元素(
display为grid或inline-grid元素的直接子元素) -
多列容器(元素的
column-count不为auto,包括 ``column-count为1) -
column-span为all的元素始终会创建一个新的BFC,即使该元素没有包裹在一个多列容器中。
BFC 常见问题和解决办法
- margin合并
在同一个BFC内,里面的盒子上下边距会产生合并,合并后边距以最大的边距为准。
解决办法就是让他们不要在同一个BFC内,做法就是将里面的元素各自利用规则创建新的BFC,比如使用float、overflow、display等选项 - 一个div内浮动元素和非浮动元素重叠了。
解决办法就是将这个浮动元素和非浮动元素的外面那个div设置成BFC,因为BFC内浮动元素不会重叠。 - 一个div内有浮动元素,结果这个div的高度小于浮动元素的高度
解决问法就是将这个div设置成BFC,因为BFC内的东西不会影响到外部布局,外部也不会影响内部,所以就撑开了
总结
所以我们知道,一个页面中有IFC、BFC、还有其他的FC如flex。每一种FC都是页面用来记录描述该区域布局方式的。在满足BFC的创建规则时就会创建一个BFC,从而运用BFC的规则。而我们所需要做得就是识别BFC的存在,并利用这些规则去避免一些布局上的不可思议。