目录标题
CSS样式中的包含块
一个元素的尺寸和位置经常受其包含块(containing block)的影响。包含块(containing block)就是元素用来计算和定位的一个框。
确定一个元素的包含块
position属性
常用的position属性值有四种:
- static 默认值,元素没有开启定位
- absolute 开启元素绝对定位
- relative 开启元素相对定位
- fixed 开启元素固定定位(固定定位也是绝对定位的一种)
- sticky
确定包含块
当前元素的定位如果
-
不是绝对定位(也就是 不是absolute或fixed),包含块可能由它的最近的祖先块元素(比如说inline-block, block 或 list-item元素)的内容区的边缘组成。
-
如果 position 属性为 absolute ,包含块就是由它的最近的 position 的值不是 static (也就是值为fixed, absolute, relative 或 sticky)的祖先元素的内边距区的边缘组成。
-
如果 position 属性是 fixed,包含块是视口。
-
如果 position 属性是 absolute 或 fixed,包含块也可能是由满足以下条件的最近父级元素的内边距区的边缘组成的:
transform 或 perspective 的值不是 none
包含块会影响哪些属性的百分比属性值的设置
元素的尺寸及位置,常常会受它的包含块所影响。对于一些属性,例如 width, height, padding, margin,绝对定位元素的偏移值 (比如 position 被设置为 absolute 或 fixed),当我们对其赋予百分比值时,这些值的计算值,就是通过元素的包含块计算得来。
如果将一个元素的以下属性值设置为百分比,那么他们的参考基准是:
- width : 相对于包含块的宽度
- height :相对于包含块的高度
- padding :padding的所有值(上下左右)都是相对于包含块的宽度
- margin :margin的所有值(上下左右)都是相对于包含块的宽度
- left/right : 相对于包含块的宽度
- top/bottom: 相对于包含块的高度
举例
非绝对定位元素的包含块
例1-1:包含块
p 标签设置为static定位,所以它的包含块是距离它最近的父节点,也就是<div>
的**content-box(内容区)**的边缘组成 。
div 如果设置有padding是不会影响百分比的计算方式的。
p 标签的margin和padding和width都是基于div元素的宽度width属性来计算的。
p 标签的height是基于div元素的高度height来计算的。
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
width: 400px;
/* padding不会影响下面百分比的计算 */
/* padding: 0 100px; */
height: 160px;
background: blue;
}
p {
width: 50%; /* == 400px * .5 = 200px */
height: 25%; /* == 160px * .25 = 40px */
margin: 5%; /* == 400px * .05 = 20px */
padding: 5%; /* == 400px * .05 = 20px */
background: cyan;
}
</style>
</head>
<body style="border: 1px solid red;width: 1000px;">
<div>
<p>This is a paragraph!</p>
</div>
</body>
例1-2:包含块没有设置宽度
改变一下上面这个例子:
p 标签的margin和padding和width都是基于div元素的width来计算。
如果我们没有设置div的宽度,那么div的宽度默认占满body,所以div的宽度是1000px(因为body的宽度就是1000px),P标签就根据这个占满的宽度来计算百分比。
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
/* width: 400px; */
height: 160px;
background: blue;
}
p {
width: 50%; /* == 1000px * .5 = 500px */
height: 25%; /* == 160px * .25 = 40px */
margin: 5%; /* == 1000px * .05 = 50px */
padding: 5%; /* == 1000px * .05 = 50px */
background: cyan;
}
</style>
</head>
<body style="border: 1px solid red;width: 1000px;">
<div>
<p>This is a paragraph!</p>
</div>
</body>
例1-3:包含块没有设置高度
改变一下上面的例子
如果我们没有设置div的高度
那么div的高度为0,所以在p标签中设置height为百分比会无效(就相当于没有设置高度),那么p标签的高度由文本撑开,div的高度也是由p撑开的
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
width: 400px;
/* height: 160px; */
background: blue;
}
p {
width: 50%; /* == 400px * .5 = 200px */
height: 25%; /* 无效 相当于没有设置 */
margin: 5%; /* == 400px * .05 = 20px */
padding: 5%; /* == 400px * .05 = 20px */
background: cyan;
}
</style>
</head>
<body style="border: 1px solid red;width: 1000px;">
<div>
<p>This is a paragraph!</p>
</div>
</body>
例1-4:包含块没有设置高度但被子元素撑高
p 元素的包含块是div元素
div元素没有设置高度
div元素的高度被p.p0撑高。
但是p.p1设置高度为百分比仍然无效。相当于没有设置。但是绝对定位的情况不是这样的(后面给例子说明)
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
background-color: gray;
}
p {
display: inline-block;
width: 25%; /* div宽度的百分之20% */
background-color: cyan;
margin: 0;
}
.p0 {
height: 100px;
}
.p1 {
height: 50%; /* 设置百分比的话无效 相当于没设置 因为包含块div元素的高度没有指定 */
}
</style>
</head>
<body style="border: 1px solid red;width: 1000px;">
<div>
<!-- p元素的包含块是div -->
<p class="p0">This is a paragraph!</p>
<p class="p1">This is a paragraph!</p>
</div>
</body>
例1-5:包含块必然是块元素
P 标签的包含块为 <body>
元素,因为<div>
不再是一个块容器,所以并没有形成一个格式上下文。
P 标签的宽度设置为50%,就是body的宽度的一半,也就是500px。
P 标签的高度设置为百分比的话,相当于没有设置,高度会和内容高度一样。
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
display: inline;
background: blue;
}
p {
width: 50%; /* == half the body's width */
height: 200px; /* 设置百分比的话无效 相当于没设置 因为包含块body元素的高度没有指定 */
background: cyan;
}
</style>
</head>
<body style="border: 1px solid red;width: 1000px;">
<!-- 这里将div设置为inline来做测试 -->
<!-- 但一般不会让内联元素包含块级元素 -->
<div>
<p>This is a paragraph!</p>
</div>
</body>
绝对定位元素(absolute)的包含块
例2-1:absolute定位的元素的包含块
P 元素的 position 为 absolute,所以它的包含块是<div>
,也就是距离它最近的一个 transform 值不为 none 的父元素的**padding-box(内边距区)**的边缘组成。
注意:P 元素的百分值会受其包含块的 padding 所影响(这一点和非绝对定位元素不一样)。不过,如果包含块的 box-sizing 值设置为 border-box ,就没有这个问题。
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
transform: rotate(0deg);
width: 400px;
height: 160px;
background: lightgray;
}
p {
position: absolute;
left: 5%; /* == 400*0.05 = 20px */
top: 5%; /* == 160px*0.05 = 8px */
width: 50%; /* == 400*0.5 = 200px */
height: 25%; /* == 160px*0.25 = 40px */
margin: 5%; /* == 400*0.05 = 20px */
padding: 5%; /* == 400*0.05 = 20px */
background: cyan;
}
</style>
</head>
<body style="border: 1px solid red;">
<div>
<!-- p元素的包含块是div -->
<p>This is a paragraph!</p>
</div>
</body>
例2-2:absolute定位元素的包含块
P 元素的包含块是<div>
的**padding-box(内边距区)**的边缘组成,因为 <div>
的 position 为 relative。
注意:下面的例子中div就有padding, 绝对定位元素的包含块的计算是包含内边距的。
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
position: relative;
left: 30px;
top: 30px;
width: 400px;
height: 160px;
padding: 30px 20px;
background: lightgray;
}
p {
position: absolute;
width: 50%; /* == (400px + 20px + 20px) * .5 = 220px */
height: 25%; /* == (160px + 30px + 30px) * .25 = 55px */
margin: 5%; /* == (400px + 20px + 20px) * .05 = 22px */
padding: 5%; /* == (400px + 20px + 20px) * .05 = 22px */
background: cyan;
}
</style>
</head>
<body style="border: 1px solid red;width: 1000px;">
<div>
<!-- p元素的包含块是div -->
<p>This is a paragraph!</p>
</div>
</body>
例2-3:包含块没有设置宽度
看下面的例子
如果div没有设置宽度,它的宽度加上padding会占满body的内容区,所以宽度加上左右内边距是1000px。
p元素的宽度,margin,padding都根据1000px计算。
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
position: relative;
/* width: 400px; */
height: 160px;
padding: 30px 20px;
background: lightgray;
}
p {
position: absolute;
width: 50%; /* == (960px + 20px + 20px) * .5 = 500px */
height: 25%; /* == (160px + 30px + 30px) * .25 = 55px */
margin: 5%; /* == (960px + 20px + 20px) * .05 = 50px */
padding: 5%; /* == (960px + 20px + 20px) * .05 = 50px */
background: cyan;
}
</style>
</head>
<body style="border: 1px solid red;width: 1000px;">
<div>
<!-- p元素的包含块是div -->
<p>This is a paragraph!</p>
</div>
</body>
例2-4:包含块没有设置高度
div是p的包含块
div没有设置高度,由于p的定位为absolute会脱离文档流,所以div会高度塌陷,div的高度为0
所以p元素的高度为25%, 也就是0
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
position: relative;
width: 400px;
/* height: 160px; */
background: lightgray;
}
p {
position: absolute;
width: 50%; /* == (400px) * .5 = 200px */
height: 25%; /* == 0 */
margin: 5%; /* == (400px) * .05 = 20px */
padding: 5%; /* == (400px) * .05 = 20px */
background: cyan;
}
</style>
</head>
<body style="border: 1px solid red;width: 1000px;">
<div>
<!-- p元素的包含块是div -->
<p>This is a paragraph!</p>
</div>
</body>
例2-5:包含块没有设置高度
div是p的包含块
div没有设置高度,由于p的定位为absolute会脱离文档流,所以div会高度塌陷,div的高度为0,但是div有上下内边距20px
所以p元素的高度为25%, 也就是(20px+20px)*0.25
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
position: relative;
width: 400px;
/* height: 160px; */
padding: 20px;
background: lightgray;
}
p {
position: absolute;
width: 50%; /* == (400px) * .5 = 200px */
height: 25%; /* == (20px+20px)*0.25 = 10px */
margin: 5%; /* == (400px) * .05 = 20px */
padding: 5%; /* == (400px) * .05 = 20px */
background: cyan;
}
</style>
</head>
<body style="border: 1px solid red;width: 1000px;">
<div>
<!-- p元素的包含块是div -->
<p>This is a paragraph!</p>
</div>
</body>
例2-6:包含块没有设置高度但被子元素撑高
p元素的包含块div没有设置高度,但是p.p0设置了高度为400px,把div的高度撑高成了400px。
注意这里和非绝对定位元素的情况不一致。
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
position: relative;
/* transform: rotate(0deg); */
width: 400px;
/* height: 160px; */
background: lightgray;
}
.p0 {
position: static;
display: inline-block;
width: 20%;
height: 400px;
margin: 0;
background: cyan;
}
.p1 {
display: inline-block;
position: absolute;
width: 20%; /* == (400px) * .2 = 80px */
height: 25%; /* == (400px) * .25 = 100px */
margin: 5%; /* == (400px) * .05 = 20px */
padding: 5%; /* == (400px) * .05 = 20px */
background: cyan;
}
</style>
</head>
<body style="border: 1px solid red;width: 1000px;">
<div>
<!-- p元素的包含块是div -->
<p class="p0">This is a paragraph!</p>
<p class="p1">This is a paragraph!</p>
</div>
</body>
绝对定位元素(fixed)的包含块
例3
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
width: 400px;
height: 480px;
margin: 30px;
padding: 15px;
background: lightgray;
}
p {
position: fixed;
width: 50%; /* == 视口宽度的一半 */
height: 50%; /* == 视口高度的一半 */
margin: 5%;
padding: 5%;
background: cyan;
}
</style>
</head>
<body style="border: 1px solid red;width: 1000px;">
<div>
<!-- p元素的包含块是div -->
<p>This is a paragraph!</p>
</div>
</body>