10.3 包含块 containing block

包含块用于两大基准:绝对级别定位基准、尺寸百分比基准。


10.3.1 为什么引入包含块概念

“position: absolute表示当前元素相对于坐标基准元素进行定位”,这句表述存在两个疑问:坐标基准元素是哪个元素?坐标基准元素是一个盒子,盒子模型包含4个部分:content、padding、border、margin,以坐标top30px与left40px为例,两个值具体相对于哪个区域?

img

因为不同场景下,基准元素不同,相对区域也不同(可能是内容区、padding区等),所以为方便描述,这个元素的这个区域统一叫做包含块containing block。例如:“position: absolute表示当前元素相对包含块进行定位”。一个元素的包含块是它某个祖先元素的某个区域。一个元素的包含块containing block小结如下:

(1)它不是元素(盒子),是元素的某块区域。它是这个元素的某个祖先元素。

(2)不同场景下,基准元素不同,基准区域不同。


10.3.2 包含块的判定规则

(1)如果元素position是static、 relative或sticky,包含块containing block是最近的祖先块容器的内容区,即父元素的内容区。

(2)如果元素position: fixed,包含块是浏览器窗口的viewport区。

(3)如果元素position: absolute,包含块是最近非static的祖先元素的padding区。


10.3.3 定位坐标与包含块

根据position属性各值的定义,只有absolute与fixed元素是相对所在包含块定位,所以只有它们两个值的坐标设置分别使用判定规则的第2条与第3条。

(1)上节absolute示例,为基准元素添加padding-bottom值,box1会随之下移,说明所在包含块代表的区域不是内容区而是padding区。

(2)上节fixed示例,body元素甚至html元素添加padding-top不影响div2的位置,说明包含块不是页面元素区域而是viewport区域。


10.3.4 width百分比

当元素设置百分比宽高时,同样采用包含块作为尺寸基准。百分比尺寸充分使用包含块的3条判定规则。总体公式如下。

width属性绝对值 = 所在包含块的宽度 * width属性百分比

场景1:static正常流定位元素。按判断规则1,所在包含块是父元素内容区。

width属性绝对值 = 父元素的内容区宽度 * width属性百分比

无论box-sizing使用content-box还是border-box,上述公式都成立。假如使用content-box,当子元素设置width: 100%,然后再设置padding与border,则子元素宽度超出父元素宽度。border-box则不会出现这种场景,可见border-box比content-box适用。


示例代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>小步教程</title>

    <style>
        .div1{
            box-sizing: border-box;
            background-color: #0aaa76;
            width: 310px;
            padding: 5px;
        }

        .div3{
            box-sizing: border-box;
            background-color: #ed7d31;
            width: 50%;
        }
    </style>
</head>
<body>
    <div class="div1">
        <div class="div3">
            <div class="div3-1">小步教程</div>
            <div class="div3-2">xiaobuteach.com</div>
        </div>
    </div>
</body>
</html>

div3包含块是div1内容区宽度310-5*2=300px,则div3的width属性绝对值150px。

运行效果。开发者工具计算样式查看width属性值一致。

img


场景2:absolute元素百分比。所在包含块是最近非static祖先元素padding区。

width属性绝对值 = 最近非static祖先元素padding区的宽度 * width属性百分比

示例代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>小步教程</title>

    <style>
        .div1{
            box-sizing: border-box;
            background-color: #0aaa76;
            width: 310px;
            height: 90px;
            padding: 5px;
        }

        .div2{
            box-sizing: border-box;
            background-color: #4aa6fc;
            width: 200px;
            padding: 5px;            
        }

        .div3{
            box-sizing: border-box;
            background-color: #ed7d31;
            width: 50%;
            bottom: 5px;

            left: 30px;
            margin-left: 10px;
        }

    </style>
</head>
<body>
    <div class="div1" style="position: relative;">
        <div class="div2">
            <div>div2</div>
            <div class="div3" style="position: absolute;">
                <div class="div3-1">小步教程</div>
                <div class="div3-2">xiaobuteach.com</div>
            </div>
        </div>
    </div>
</body>
</html>

div3基准元素是div1,但与上例不同的是,包含块是div1的padding区(含内容区)。padding区宽度310,则div3的width属性绝对值155px。

运行效果

img

查看div3的盒子模型,与分析一致。

img

通过属性offsetParent验证absolute元素的包含块对应元素。开发者工具查看div3的offsetParent是div1,关系一致。

img

试一试。div2元素设置position: relative,div3的包含块containing block是哪个元素。


场景3:fixed元素百分比。所在包含块是浏览器窗口内容区viewport。

width属性绝对值 = viewport的宽度 * width属性百分比

示例代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>小步教程</title>

    <style>
        .div1{
            box-sizing: border-box;
            background-color: #0aaa76;
            width: 310px;
            height: 90px;
            padding: 5px;
        }

        .div2{
            box-sizing: border-box;
            background-color: #4aa6fc;
            width: 200px;
            padding: 5px;            
        }

        .div3{
            box-sizing: border-box;
            background-color: #ed7d31;
            width: 50%;
            bottom: 5px;
        }
    </style>
</head>
<body>
    <div class="div1">
        <div class="div2">
            <div>div2</div>
            <div class="div3" style="position: fixed;">
                <div class="div3-1">小步教程</div>
                <div class="div3-2">xiaobuteach.com</div>
            </div>
        </div>
    </div>
</body>
</html>

浏览器窗口宽度调至最小500px,则div3的width属性绝对值250px。

运行效果

img

通过属性offsetParent验证absolute元素的包含块对应元素。没有offsetParent属性,表示是viewport。wdith值也一致。

img


10.3.5 其它属性百分比

(1)盒子模型的属性width、height、padding、margin能够使用百分比,border距离不能使用百分比。

(2)width、padding、margin四个方向百分比是相对包含块的width值。例如padding-top、margin-top等垂直方向值也是相对于width而不是height。

(3)坐标属性top、bottom、left、right能够使用百分比。

(4)top、bottom相对于包含块的height;left、right相对于width。

包含块概念经常被忽视。理解这个概念不仅学习一些细节,更是代表页面分析设计方法。CSS的很多概念与术语同理,本质是表达分析设计方法。