此文的参考资料:
- 前端精选文摘:BFC 神奇背后的原理
- CSS 2.1 block-formatting
示例代码均使用Pug和Sass编写。
float
① float设计的初衷:文字环绕效果
//
② float的特性
特性一:设置了float的元素不参与高度计算。
特性二:设置了float的元素会有包裹性的特点。
特性三:设置了float的元素会自动变成block元素。
我们先看特性一:
我们把上面代码中的p标签删剩一个。可以发现类名为text-around这个div(这个div下面简称为T-DIV)的高度只有一个p标签,即该图片不参与其父元素的高度计算。但是很奇怪的是该图片参与了根元素(<html>)的高度计算!
<坑1> 预告一下这个奇怪的现象跟BFC有关,具体原因下面BFC那一块再讲。
再来看特性二:
我们看看图2中的T-DIV,可以发现其宽度很大(实际上其宽度为父元素的100%),但是高度只有一个p标签的高度。
接着我们修改一下实例代码:
//
T-DIV加了float属性后,一眼看去,该div宽度收缩了,而且此时图片也参与了高度的计算。
我们再仔细分析一下:
- 先看宽度,‘文字环绕效果文字环绕效果’十二个字的宽度为192px,图片的宽度为100px。而text-around这个div最终收缩的宽度为192px,由此可得收缩的宽度取决于内部元素的最大宽度。
- 再看高度,T-DIV的高度与图片高度相同,可见图片即使设置了float属性也会参与T-DIV的高度计算(<坑2> 其实这也是BFC的一个特性,下面会详细介绍)。
- 文字环绕效果,图片的float触发了文字环绕效果,但是由于T-DIV的宽度已经确定了,所以文字没有一行排开,而是分开了好几行。
③ 清除浮动
为什么要清除浮动?
浮动的特性一决定了其会导致父元素高度塌陷,即图2展示的情况。清除浮动其实就是清除浮动带来的父元素高度塌陷的影响。
怎么清除浮动?
方法一:使用clear: both
clear属性的值可以有left,right,both等等,设置了该属性的元素的左边或右边不能出现浮动元素。若其左边或者右边出现了浮动元素,该元素就会定位到浮动元素的下方,从而保证其左边或右边没有浮动元素。
(一)使用伪类:after:
content,height,overflow这三个属性是为了保证该伪类不会显示出任何东西,而将其设置为block是为了让其宽度占满一行,这样浮动元素才能在其范围内,clear属性才能起作用。
.text-around
(二)新增一个div
//
方法二:父元素触发BFC
<坑3> 为什么BFC能清除浮动,这个问题也留着一会讲
BFC(Block Formatting Context)
① BFC是什么
简单来讲,BFC就是一个容器,而这个容器内的块级元素会遵循一系列规则。
② 怎么触发BFC
- 根元素(<html>)
- float属性不为none
- position为absolute或fixed
- display为inline-block, table-cell, table-caption, flex, inline-flex
- overflow不为visible
③ BFC内块级元素遵循的规则
- 块级元素从顶部开始,一个接一个地垂直排列的。
- 块级元素垂直方向的距离由margin决定,并且属于同一个BFC的两个相邻块级元素的margin会发生重叠。
- 每个块级元素的左外缘与包含块的左边缘接触(对于从右到左格式,右边缘接触)。即使存在浮动,也会出现这种情况
针对第二点,可以想出,边距重叠的解决方案为:两个块元素中其中一个触发生成BFC(这样两个块元素就不属于同一个BFC,因此就不满足第二点触发的条件)
针对第三点,先提出包含块的概念。众所周知,一个完整的box包含margin-box,border-box,padding-box,content-box,但是包含块只能是content-box或者padding-box。
- 若一个块级元素的position为fixed。那么,包含块始终都为viewport。
- 若一个块级元素的position为absolute。那么,包含块则为离它最近的position不是static的祖先元素的padding-box 。
- 若一个块级元素的position为static或relative。那么,包含块则为其父元素的content-box。
第三点也是文字环绕效果的实现原理。先看个例子:
//
p标签的包含块即为T-DIV,因此p标签的margin-box会与T-DIV的content-box左边缘接触,故而出现图5的情况。
④ BFC的特性
- BFC的区域不会与float box重叠。
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
- 计算BFC的高度时,浮动元素也参与计算。
⑤ 填坑
有了上述的对BFC的介绍,终于可以愉快地填坑了。
坑1、坑2、坑3这三种情景的根本原因都是因为BFC特性的第三点:计算BFC的高度时,浮动元素也参与计算。下面一个个来看:
<填坑1> 回顾一下坑1,设置的float的图片居然参与了根元素(<html>)的高度计算!
A:发生这个情况的原因是根元素(<html>)本身就会触发一个BFC。
<填坑2> 回顾一下坑2,图片即使设置了float属性也会参与T-DIV的高度计算!
A:T-DIV在设置了float:left的时候使T-DIV触发了BFC。
<填坑3> BFC为什么能清除浮动?
A:因为BFC中浮动元素也参与计算高度,因此就清除了浮动带来的父元素高度塌陷的影响。