布局和包含块
一个元素的尺寸和位置通常受其包含块的影响。大多数情况下,包含块是该元素最近的块级祖先元素的内容区,但情况并非总是如此。在本文中,我们将探讨决定元素包含块的因素。
当用户代理(如你的浏览器)布局一个文档时,它会为每个元素生成一个盒子。每个盒子被分为四个区域:
- 内容区
- 内边距区
- 边框区
- 外边距区
许多开发者认为,元素的包含块总是其父元素的内容区,但这不一定正确。让我们来研究一下决定元素包含块的因素。
包含块的影响
在学习什么决定了元素的包含块之前,了解它为什么重要是很有用的。
元素的尺寸和位置通常受其包含块的影响。应用于元素的 width
、height
、padding
、margin
,以及绝对定位元素(即其 position
设置为 absolute
或 fixed
)的偏移属性的百分比值,都是根据其包含块计算的。
确定包含块
确定包含块的过程完全取决于元素 position
属性的值:
- 如果
position
属性是static
、relative
或sticky
,包含块由最近的祖先元素的内容盒(content box)的边缘构成,该祖先元素要么是块容器(例如 inline-block、block 或 list-item 元素),要么建立了格式化上下文(例如 table 容器、flex 容器、grid 容器或块容器本身)。 - 如果
position
属性是absolute
,包含块由最近的position
值不是static
(即fixed
、absolute
、relative
或sticky
)的祖先元素的内边距盒(padding box)的边缘构成。 - 如果
position
属性是fixed
,包含块由视口(对于连续媒体)或页面区域(对于分页媒体)建立。 - 如果
position
属性是absolute
或fixed
,包含块也可能由最近的具有以下任一属性的祖先元素的内边距盒(padding box)的边缘构成:- 一个值不为
none
的filter
、backdrop-filter
、transform
或perspective
属性。 contain
属性的值为layout
、paint
、strict
或content
(例如,contain: paint;
)。container-type
的值不为normal
。will-change
属性的值包含某个属性,该属性的非初始值会形成包含块(例如filter
或transform
)。content-visibility
属性的值为auto
。
- 一个值不为
备注: 根元素(<html>
)所在的包含块是一个被称为初始包含块的矩形。它的尺寸为视口(对于连续媒体)或页面区域(对于分页媒体)的大小。
备注: 在 perspective
和 filter
属性对包含块形成的影响上存在浏览器不一致性。
根据包含块计算百分比值
如上所述,当某些属性被赋予百分比值时,其计算值取决于元素的包含块。以这种方式工作的属性是盒模型属性和偏移属性:
height
、top
和bottom
属性根据包含块的height
来计算百分比值。width
、left
、right
、padding
和margin
属性根据包含块的width
来计算百分比值。
备注: 一个块容器(如 inline-block、block 或 list-item 元素)要么只包含参与行内格式化上下文的行内级盒子,要么只包含参与块级格式化上下文的块级盒子。一个元素只有在它包含块级或行内级盒子时才是块容器。
一些示例
我们所有示例的 HTML 代码如下:
<body>
<section>
<p>This is a paragraph!</p>
</section>
</body>
下面的每个实例只修改了 CSS。
示例 1
在此示例中,段落是静态定位的,因此其包含块是 <section>
,因为它是最近的作为块容器的祖先(由于 display: block
)。
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;
}
示例 2
在此示例中,段落的包含块是 <body>
元素,因为 <section>
不是块容器(由于 display: inline
)并且没有建立格式化上下文。
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;
}
示例 3
在此示例中,段落的包含块是 <section>
,因为后者的 position
是 absolute
。段落的百分比值受到其包含块 padding
的影响,但如果包含块的 box-sizing
值为 border-box
,则情况并非如此。
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;
}
示例 4
在此示例中,段落的 position
是 fixed
,所以它的包含块是初始包含块(在屏幕上是视口)。因此,段落的尺寸会根据浏览器窗口的大小而改变。
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;
}
示例 5
在此示例中,段落的 position
是 absolute
,所以它的包含块是 <section>
,它是最近的具有不为 none
的 transform
属性的祖先。
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;
}
另见
all
属性contain
属性aspect-ratio
属性box-sizing
属性min-content
和max-content
尺寸值- 学习:在 CSS 中调整项目大小
- 盒模型
- CSS 盒模型模块
- 布局模式
- 视觉格式化模型
- 块格式化上下文
- 层叠上下文
- 外边距折叠
- 初始值、计算值、使用值和实际值
- 替换元素
- 固有尺寸