10.3 包含块 containing block
包含块用于两大基准:绝对级别定位基准、尺寸百分比基准。
10.3.1 为什么引入包含块概念
“position: absolute表示当前元素相对于坐标基准元素进行定位”,这句表述存在两个疑问:坐标基准元素是哪个元素?坐标基准元素是一个盒子,盒子模型包含4个部分:content、padding、border、margin,以坐标top30px与left40px为例,两个值具体相对于哪个区域?
因为不同场景下,基准元素不同,相对区域也不同(可能是内容区、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属性值一致。
场景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。
运行效果
查看div3的盒子模型,与分析一致。
通过属性offsetParent验证absolute元素的包含块对应元素。开发者工具查看div3的offsetParent是div1,关系一致。
试一试。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。
运行效果
通过属性offsetParent验证absolute元素的包含块对应元素。没有offsetParent属性,表示是viewport。wdith值也一致。
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的很多概念与术语同理,本质是表达分析设计方法。