CSS 的包含块是如何决定元素的尺寸和位置?

本文详细解析了CSS中包含块的概念及其对元素尺寸和位置的影响。重点介绍了如何根据元素的不同position属性确定其包含块,以及如何从包含块计算百分比值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、包含块

笔者在学习 CSS In Depth 的 3.2.2 节时,被一个关于关于元素百分比循环定义困住了:

Percentage refers to the size of an element’s containing block; the height of that container, however, is typically determined by the height of its children. This produces a circular definition that the browser can’t resolve, so it’ll ignore the declaration. For percentage-based heights to work, the parent must have an explicitly defined height.

百分比是相对于元素的包含块的尺寸而言的;然而,该容器的高度通常由其子元素的高度决定。这就形成了一个浏览器无法处理的循环定义,因此会忽略该声明。要让基于百分比的高度生效,父元素必须具有明确定义的高度。

今天来学习 CSS 中的 Containing Block 包含块,相信学完之后,你同样能够对这个问题的答案醍醐灌顶。

今天解析的文章是来自关于包含块的 MDN 文章

一个元素的尺寸和位置经常被包含块所影响。大部分情况下,包含块指向一个元素最近的块级祖先元素的内容区域,小部分情况下不是这样的。在这篇文章中,我们会研究那些确定一个元素包含块的因素。

虽然这里翻译为祖先元素(ancestor),但其实更贴切是长辈元素,因为这里不仅指祖先元素,也指父类元素。想象一下,一个 <div> 被嵌套了几层,它的包含块就是第一个遇到的外层块级元素(注意是块级元素,也就是会忽略掉内联元素),第一个遇到的无论是父类还是祖父类们,都可以。

当一个用户代理(例如你的浏览器)展开一份文档,它会为每个元素生成一个盒子,每个盒子可以分成四个区域:

  1. 内容区域
  2. 内边距区域
  3. 边框区域
  4. 外边距区域

其实也就是盒模型。

许多开发者坚信一个元素的包含块一定是它父类的内容区域,但这一结论不一定总是成立。让我们来研究一下确定一个元素的包含块的因素。

这里重复强调了下,元素的包含块是根据不同条件确定的。

二、包含块的效果

image-20220113223746573.png

在我们学习确定一个元素的包含块之前,了解一下为什么包含块的作用性是很重要的。

一个元素的尺寸和位置经常被它的包含块所影响。应用在 width, height, padding, margin 上的百分比值,还有 absolute 定位的元素偏移属性,都是根据元素的包含块计算出来的。

像百分比这样的值,肯定根据一个基准来进行计算,得到最后的结果值,而包含块就是那个基准。

三、标识一个包含块

标志包含块的程序完成取决于元素的 position 属性

  1. 如果 position 属性是 static, relative 或者 sticky,包含块通过最近长辈元素的内容盒的边界来形成,这个长辈元素可以是一个块级容器(例如 inline-block, block 或者 list-item元 素),也可以是建立了格式化的上下文(例如一个 table 容器,flex 容器,grid 容器,或者块级容器本身)

一个元素如果不显示定义 position 的值的话,那么元素 position 的默认值为 static。大部分元素都是不定义 position 值的,也就导致了前文提到的:许多开发者坚信一个元素的包含块一定是它父类的内容区域

  1. 如果 position 的属性值是 absolute,包含块变成了最近的长辈元素的内边距区域,这个最近的长辈元素指它的 position 属性值不是 static(可以是 fixed, absolute, relative 或者 sticky)的元素。

注意包含块的变化,position 的值从 static 的最近长辈元素的内容区域(见下图绿色线条区域)改为 absolute 确定的最近长辈元素的内边距区域(下图红色线圈出来的区域,是包括内边距的边缘的)。

❔ 为什么内容区域变为了内边距区域?

这样做的目的是为了忽略内边距,体现了绝对定位(absolutely position)的效果

如果position属性是fixed,包含块由窗口(在连续媒体情况下)或者页面区域(在页面媒体情况下)所确定。

根据 MDN 的另一篇文章,连续媒体一般指音频或者运动视频。

  1. 如果 position 的属性是 absolute 或者 fixed,包含块同样会变成最近长辈元素的内边距区域,这个最近的长辈元素符合下面条件:
    1. transform 或者 perspective 的值不是 none
    2. will-change 属性值是 transform 或者 perspective
    3. filter 的值不是 none 或者 will-change 的值不是 filter(仅在 firefox 有效);
    4. contain 的值是 paint(例如:contain: paint;)。

will-change 这个比较少见,它是CSS的一个属性,作用是向浏览器表明元素即将做出变化,浏览器因此可以对此进行针对性的优化,从而提高页面响应性能。

包含根元素(<html>)的矩形包含块称之为初始包含块。它有视口(对于连续媒体)或者页面区域(对于页面媒体)的尺寸。

根元素 <html> 也有他自己的包含块,那么对于 html 页面上每一个元素来说,都会拥有自己的包含块。

四、从包含块中计算百分比值

如上所述,但某个属性给定一个百分比值,它计算出来的结果取决与元素的包含块。这些属性包括盒模型属性还有偏移属性:

  1. height, top 还有 bottom 属性从包含块的 height 中计算它的百分比值
  2. width, left, right, padding 还有 margin 属性从它的包含块的 width 中计算它的百分比值。

五、一些例子

以下是一段简单的html代码:

<body>
  <section>
    <p>This is a paragraph!</p>
  </section>
</body>

以下例子共用上面这一份 HTML 代码,只是 CSS 代码有所变化,当这些 CSS 代码变化的时候,推断一下元素的包含块,以及元素的百分比计算结果。

例1

body {
  background: beige;
}

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

p {
  width: 50%;  
  height: 25%;  
  margin: 5%;  
  padding: 5%; 
  background: cyan;
}

在这个例子中,<p>position 属性 是static,它的包含块是 <section>,因为它是块级容器,并且也是距离 <p> 最近的长辈元素。

那么,<p>的各个百分比值计算等于

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

marginpadding 的属性值为百分比,他们的计算规则遵循:

width, left, right, padding 还有 margin 属性从它的包含块的 width 中计算它的百分比值。

例2

body {
    background-color: beige;
}

section {
    display: inline;
    background: lightgray;
}

p {
    width: 50%;
    height: 200px;
    background-color: cyan;
}

在这个例子中,<p> 的包含块是 <body> 元素,因为 <section> 不是一个块级容器(因为display: inline)并且也没有建立格式化上下文。

<p> 的宽度百分比计算如下:

p {
    width: 50%; /* 值等于 <body> 宽度的一半 */
    height: 200px;
    background-color: cyan;
}

例3

body {
    background-color: beige;
}

section {
    position: absolute;
    left: 30px;
    top: 30px;
    width: 400px;
    height: 160px;
    padding: 30px 20px;
    background: lightgray;
}

p {
    position: absolute;
    width: 50%;  
    height: 25%; 
    margin: 5%;  
    padding: 5%; 
    background-color: cyan;
}

在这里例子中,<p> 的包含块是 <section> 因为后者的 position 值是 absolut<p> 的百分比值会被包含块的 padding 所影响,如果包含块的 box-sizing 属性值是 border-box 的话,那么情况就不一样了。

<p> 的宽度百分比计算如下:

p {
    position: absolute;
    width: 50%;  /* (400+20*2)px*50%=220px */
    height: 25%; /* (160+30*2)px*25%=55px */
    margin: 5%;  /* (400+20*2)px*5%=22px */
    padding: 5%; /* (400+20*2)px*5%=22px */
    background-color: cyan;
}

box-sizing: border-box; 属性的作用是 widthheight 包含 content+padding+margin,也就是 IE 盒模型(标准的 W3C 盒模型 widthheight 只指定 content,不包含 padding 和 margin)。

<section> 添加了 box-sizing: border-box;,那么 <p> 的宽度百分比计算会变为:

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

这里读者可以自行验证下。

例4

body {
    background-color: beige;
}

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

p {
    position: fixed;
    width: 50%;   
    height: 50%; 
    margin: 5%; 
    padding: 5%;
    background-color: cyan;
}

在这个例子中,<p>positionfixed,所以它的包含块是初始包含块(在屏幕上,那个视窗)。因此,<p> 的尺寸根据浏览器窗口的尺寸改变而改变。

<p> 的各个属性百分比计算如下:

p {
    /* 假设视窗的宽高比为:562px*612px*/
    position: fixed;
    width: 50%;   /* 562px*50%=281px */
    height: 50%;  /* 612px*50%=306px */
    margin: 5%;   /* 562px*5%=28.1px */
    padding: 5%;  /* 562px*5%=28.1px */
    background-color: cyan;
}

这里的视窗尺寸可以用浏览器的小手机图标来模拟:

例5

body {
    background-color: beige;
}

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

p {
    position: absolute;
    left: 80px;
    top: 30px;
    width: 50%;  
    height: 25%; 
    margin: 5%;  
    padding: 5%; 
    background-color: cyan;
}

在这个例子中,<p>positionabsolute,所以它的包含块是<section><section>transform属性不为none,所以它能够称为<p>的最近长辈元素。

<p>的各个属性百分比计算如下:

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

六、总结

看到这里的话,恭喜你完成了对包含块的所有学习 🎉🎉🎉

我们来总结下,包含块就是用于确定元素的尺寸和位置的,每一个元素都拥有自己的包含块(<html> 的包含块称之为初始包含块)。

如果 positionstatic, relative, sticky,那么元素的包含块是最近的长辈元素(displayblock, table, flex, grid 元素的内容区域)。

如果是 absolute,那么是内边距区域。

如果是 fixed,那么由视窗来决定。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值