8.4 BFC模型的规范规则
BFC模型内部只有并列或嵌套的块级元素。本章后续出现的“元素”、“盒子”如未特殊说明,均指块级元素、块级盒子。现在开始研究这一表面上最简单的模型。BFC模型是经常忽视的一个模型,似乎只有一个规范规则“margin折叠”需要学习它。有时会认为margin折叠规则是一个糟糕的设计,有时又是合理到感觉不到它的存在。
讲解margin折叠前先介绍两个重要概念:属于同一BFC、新建BFC。
8.4.1 BFC定义
流式布局里的普通块级元素,在同一个块格式化上下文BFC。这里只是给出“属于同一BFC”的判断规则,或者说定义了“同一BFC”,没有给出严格的BFC定义。
8.4.2 BFC规范规则1:根元素新建BFC对象
如果一个页面只有普通块级元素与行内元素,则页面只有根元素html在自己内部创建唯一BFC对象,记作BFC-root,其它元素由BFC-root管理,也称:这些元素参与到BFC-root。
元素与BFC的关系分为两种:创建,元素在自己内部创建BFC对象;参与,元素参与到祖先元素(外部)已经创建的BFC对象。
示例代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>小步教程</title>
<style>
body{
font-size: 16px;
line-height: 30px;
}
span {
border: 1px solid #ddd;
padding: 0 30px;
margin: 10px 0;
}
div{
margin: 10px 0;
border: 1px solid #bbb;
padding: 0 10px;
}
</style>
</head>
<body>
<div id="div1">
<span id="span1">div1 span1</span>
<span id="span2">span2</span>
<span id="span3">span3</span>
<span id="span4">span4</span>
<span id="span5">span5</span>
</div>
<div id="div2">div2 小步教程 xiaobuteach.com</div>
<div id="div3">
<div id="div3_1">div3 div3_1</div>
<div id="div3_2">
<span>div3_2 span6</span>
</div>
</div>
<div id="div4">
<span id="span8">div4 span7</span>
<span id="span9">span8</span>
</div>
</body>
</html>
BFC示意图如下
根元素html内部创建BFC对象,记作BFC-root;body与其它6个div参与到BFC-root,也就是由BFC-root管理,它们都不会在内部新建BFC对象。由此可见,一个元素(除根元素)总是参与到一个BFC,一个元素的内部可能新建BFC或者不新建BFC。
BFC对象名称(例如BFC-root)是自定义名称,用于区分多个BFC,页面与开发者工具不存在这个名称。各个span参与到相应IFC对象,BFC不直接管理span。
display-inside: flow与BFC的关系。html、body、div具有相同样式display: block,完整写法block flow。display-inside: flow的含义包括两种情况:一般表示参与到已有BFC;特殊元素新建BFC,例如html元素总是新建BFC。
8.4.3 BFC规范规则2:特殊元素新建BFC对象
下列元素会在内部新建BFC。这里仅列举常见场景。
(1)脱离流的元素。包括:float元素(不为none)、绝对级别定位元素(absolute与fixed)。
(2)flex、table、grid的布局结构末级元素。例如:flex子元素、th、td、grid子元素。
(3)非inline的inline级元素。例如: inline-block、inline-flex、inline-table、inline-grid。
(4)display-inside值flow-root的元素。
(5)overflow值不是visible或clip的元素。
示例代码。上述代码为div3设置样式。
#div3{
position: absolute;
right: 10px;
top: 37px;
background-color: #fff;
}
运行效果
BFC示意图
现在存在2个BFC。
(1)BFC-root。属于BFC-root管理的元素:body、div1~div4。
(2)absolute的div3在内部新建BFC-2对象。BFC-2管理元素:div3-1、div3-2。
问题:为什么div3不属于BFC-2管理?BFC内外两层的逻辑与display内外两层的逻辑非常相似,不存在自我管理而是逐级管理。一个元素内部新建BFC时,新BFC管理它的内部(后代)元素,该元素仍由所在BFC管理。div3虽然特殊,但它的位置仍然由所在BFC即BFC-root计算;div3本身特殊,div3希望自己的内部正常,所以div3为内部元素创建BFC-2。
BFC逐级嵌套。实际项目页面通常有更多BFC,BFC之间互相间接嵌套,例如html元素内部新建BFC-root,BFC-root包含特殊元素div2与div3,div2与div3内部分别新建BFC-2与BFC-3,BFC-2包含特殊元素div-2-1,div-2-1内部新建BFC-2-1。BFC逐级嵌套对应display模型逐级嵌套。
8.4.4 BFC规范规则3:同一BFC内各盒子的规范规则
(1)理所当然型规则。内部盒子从顶部开始,依次垂直排列;内部相邻盒子之间的垂直间距由margin决定;内部盒子的左边靠近块级父容器的左边。
(2)特殊型规则。margin折叠:当两个相邻元素的垂直方向的margin相邻,则可能发生margin区域的部分重叠或者完全重叠,这种现象叫做margin折叠。
正如讲解BFC时,块级盒子省略成盒子,垂直margin也省略成margin,因为水平margin不会发生折叠。