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示意图如下

img

根元素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;
        }

运行效果

img


BFC示意图

img

现在存在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不会发生折叠。