布局和包含块

一个元素的尺寸和位置受其包含块的影响,大部分情况下元素的包含块就是最近祖先块元素的内容区域(盒模型的content)

根据包含块计算百分值

  • height、top、bottom属性根据包含块的height计算
  • width、left、right、margin、padding属性根据包含块的width计算

确定包含块

确定一个元素的包含块的过程依赖于属性position的值:

  • 如果position的值为static、sticky、relative,包含块可能为最近的祖先块元素的内容区域
  • 如果position的值为absolute,包含块为最近position不为static的祖先元素的内边距区域
  • 如果position的值为fixed,在连续媒体的情况下包含块是viewport视口,分页媒体的情况下包含块是分页区域
  • 如果position的值为absolute或fixed的,包含块也可能是由满足以下条件的最近父级元素的内边距区的边缘组成的:
    • transform 或 perspective 的值不是 none
    • will-change 的值是 transform 或 perspective
    • filter 的值不是 none 或 will-change 的值是 filter(只在 Firefox 下生效)。
    • contain 的值是 layout、paint、strict 或 content(例如:contain: paint;)
    • backdrop-filter 的值不是 none(例如:backdrop-filter: blur(10px);)

示例

这个示例中,P 标签设置为静态定位,所以它的包含块为 <section>,因为距离最近的父节点即是她的包含块。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
body {
background: beige;
}

section {
display: block;
width: 400px;
height: 160px;
background: lightgray;
}

p {
width: 50%; /* == 400px * .5 = 200px */
height: 25%; /* == 160px * .25 = 40px */
margin: 5%; /* == 400px * .05 = 20px */
padding: 5%; /* == 400px * .05 = 20px */
background: cyan;
}

在这个示例中,P 标签的包含块为 <body> 元素,因为 <section> 不再是一个块容器,所以并没有形成一个格式上下文。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
body {
background: beige;
}

section {
display: inline;
background: lightgray;
}

p {
width: 50%; /* == half the body's width */
height: 200px; /* Note: a percentage would be 0 */
background: cyan;
}

这个示例中,P 元素的包含块是 <section>,因为 <section> 的 position 为 absolute 。P 元素的百分值会受其包含块的 padding 所影响。不过,如果包含块的 box-sizing 值设置为 border-box ,就没有这个问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
body {
background: beige;
}

section {
position: absolute;
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;
}

这个示例中,P 元素的 position 为 fixed,所以它的包含块就是初始包含块(在屏幕上,也就是 viewport)。这样的话,P 元素的尺寸大小,将会随着浏览器窗框大小的变化,而变化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
body {
background: beige;
}

section {
width: 400px;
height: 480px;
margin: 30px;
padding: 15px;
background: lightgray;
}

p {
position: fixed;
width: 50%; /* == (50vw - (width of vertical scrollbar)) */
height: 50%; /* == (50vh - (height of horizontal scrollbar)) */
margin: 5%; /* == (5vw - (width of vertical scrollbar)) */
padding: 5%; /* == (5vw - (width of vertical scrollbar)) */
background: cyan;
}

这个示例中,P 元素的 position 为 absolute,所以它的包含块是<section>,也就是距离它最近的一个 transform 值不为 none 的父元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
body {
background: beige;
}

section {
transform: rotate(0deg);
width: 400px;
height: 160px;
background: lightgray;
}

p {
position: absolute;
left: 80px;
top: 30px;
width: 50%; /* == 200px */
height: 25%; /* == 40px */
margin: 5%; /* == 20px */
padding: 5%; /* == 20px */
background: cyan;
}