想要理解BFC与IFC,首先要理解另外两个概念:Box 和 FC(即 formatting context)
一、Box
一个页面是由很多个 Box 组成的,元素的类型和 display 属性决定了这个 Box 的类型。不同类型的 Box,会参与不同的 Formatting Context。
Block level
的box会参与形成BFC,比如display值为block
,list-item
,table
的元素。Inline level
的box会参与形成IFC,比如display值为inline
,inline-table
,inline-block
的元素。
二、FC(Formatting Context)
它是W3C CSS2.1规范中的一个概念,定义的是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。 常见的Formatting Context 有:
- Block Formatting Context(BFC | 块级格式化上下文)
- Inline Formatting Context(IFC |行内格式化上下文)
三、IFC布局规则
- 在行内格式化上下文中,框(boxes)一个接一个地水平排列,起点是
包含块
的顶部 - 水平方向上的
margin
,border
和padding
在框之间得到保留 - 框在垂直方向上可以以不同的方式对齐:它们的顶部或底部对齐,或根据其中文字的基线对齐
- 包含那些框的长方形区域,会形成一行,叫做
行框
四、BFC布局规则
- 内部的Box会一个接一个地垂直放置
- 每个元素的左外边缘(margin-left), 与包含块的左边(contain box left)相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。除非这个元素自己形成了一个新的BFC。
- BFC的区域不会与float box
重叠
。 - BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
- 计算BFC的高度时,浮动子元素也参与计算
五、形成一个BFC
下列方式会创建块格式化上下文:
- 根元素或包含根元素的元素
- 浮动元素(元素的
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
或strict
的元素- 弹性元素(
display
为flex
或inline-flex
元素的直接子元素) - 网格元素(
display
为grid
或inline-grid
元素的直接子元素) - 多列容器(元素的
column-count
或column-width
不为auto,包括 `
column-count为
1`) column-span
为all
的元素始终会创建一个新的BFC,即使该元素没有包裹在一个多列容器中(标准变更,Chrome bug)
六、外边距合并
块级元素的上外边距和下外边距有时会合并(或折叠)为一个外边距,其大小取其中的最大者,这种行为称为外边距折叠(margin collapsing)
注:浮动元素和绝对定位元素的外边距不会折叠(触发了 块格式化上下文 Block Formatting Context, BFC)
下面列出了会发生外边距折叠的三种基本情况:
相邻元素之间
毗邻的两个元素之间的外边距会折叠(除非后一个元素需要清除之前的浮动)。
父元素与其第一个或最后一个子元素之间
如果在父元素与其第一个子元素之间不存在边框、内边距、行内内容,也没有创建块格式化上下文、或者清除浮动将两者的
margin-top
分开;或者在父元素与其最后一个子元素之间不存在边框、内边距、行内内容、
height
、min-height
、max-height
将两者的margin-bottom
分开,那么这两对外边距之间会产生折叠。此时子元素的外边距会“溢出”到父元素的外面。
空的块级元素
如果一个块级元素中不包含任何内容,并且在其
margin-top
与margin-bottom
之间没有边框、内边距、行内内容、height
、min-height
将两者分开,则该元素的上下外边距会折叠。
七、BFC用处
1. 清除浮动
1 | <div class="wrap"> |
1 | .wrap { |
可以看到,由于子元素都是浮动的,受浮动影响,边框为黄色的父元素的高度塌陷了。
解决方案:为 .wrap
加上 overflow: hidden
;使其形成BFC
,根据BFC规则第六条,计算高度时就会计算float的元素的高度,达到清除浮动影响的效果。
2. 防止垂直margin合并
1 | <section class="top">1</section> |
1 | section { |
可以看到,明明.top和.bottom中间加起来有200px的margin值,但是我们只能看到100px。这是因为他们的外边距相遇发生了合并。
怎样解决:为其中一个元素的外面包裹一层元素。并为这个外层元素设置 overflow: hidden;,使其形成BFC。因为BFC内部是一个独立的容器,所以不会与外部相互影响,可以防止margin合并。
1 | <section class="top">1</section> |
1 | .wrap { |
2. 布局:自适应两栏布局
1 | <div> |
1 | div { |
可以看到右侧元素的一部分跑到了左侧元素下方
注:
float元素的特点:背景重叠,文字环绕
float元素和main发生了重叠,如果float元素背景色为透明,可以看到main的背景色。
解决方案:为main设置 overflow: hidden; 触发main元素的BFC,根据规则第4、5条,BFC的区域是独立的,不会与页面其他元素相互影响,且不会与float元素重叠
,因此就可以形成两列自适应布局