理解 CSS 中的 Containing Block

前言

在开始本文之前先来看一个例子,下面一段简单的 html 代码,布局很简单:

xml 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Css Containing Block</title>
    <style>
      body {
        padding: 0;
        margin: 0;
      }
      .parent {
        height: 100px;
        width: 100px;
        background-color: red;
      }

      .child {
        position: absolute;
        top: 0;
        right: 0;
        width: 50%;
        height: 50%;
        background-color: yellow;
      }
    </style>
  </head>
  <body>
    <div>
      <div class="parent">
        <div class="child"></div>
      </div>
    </div>
  </body>
</html>
  1. 两个嵌套的 div,一个背景是红色,一个背景是黄色。
  2. div parent 设置的宽高分别是 100px、100px。
  3. div child 设置的宽高是 50%、50%。

让我们思考一下这段代码的运行效果应该是什么样子,然后看一下实际的运行结果是不是和我们思考的一样。

运行结果如下:

对于前端初学者来说可能会有这样的困惑,明明 child 的 width 和 height 分别设置的 50%、50%,那黄色背景的 child 的大小不应该是 width=50px、height=50px 吗?带着这个疑问我们来改一下代码如下:

给 parent 增加 transform: translate(20px, 20px);

css 复制代码
.parent {
  height: 100px;
  width: 100px;
  transform: translate(20px, 20px); // 添加transform
  background-color: red;
}

保存之后在浏览器里运行,再看一下效果:

这次的运行效果和我们预期的一致了,黄色背景的 child width=50px、height=50px。

理解产生这个现象的原因,我们要知道 Containing Block。

transform 是 CSS 里的一个属性,它的取值很多,利用 transform 我们可以对元素进行旋转、缩放、平移以及元素歪斜(skew)

css 复制代码
/* Keyword values */
transform: none;

/* Function values */
transform: matrix(1, 2, 3, 4, 5, 6);
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
transform: perspective(17px);
transform: rotate(0.5turn);
transform: rotate3d(1, 2, 3, 10deg);
transform: rotateX(10deg);
transform: rotateY(10deg);
transform: rotateZ(10deg);
transform: translate(12px, 50%);
transform: translate3d(12px, 50%, 3em);
transform: translateX(2em);
transform: translateY(3in);
transform: translateZ(2px);
transform: scale(2, 0.5);
transform: scale3d(2.5, 1.2, 0.3);
transform: scaleX(2);
transform: scaleY(0.5);
transform: scaleZ(0.3);
transform: skew(30deg, 20deg);
transform: skewX(30deg);
transform: skewY(1.07rad);

/* Multiple function values */
transform: translateX(10px) rotate(10deg) translateY(5px);
transform: perspective(500px) translate(10px, 0, 20px) rotateY(3deg);

/* Global values */
transform: inherit;
transform: initial;
transform: revert;
transform: revert-layer;
transform: unset;

Containing Block

在介绍 Containing Block 之前,先来复习一下 CSS 盒模型,以标准盒模型为例,html 里的每一个元素都有一个盒子,盒子由 Content、Padding、Border、Margin 组成。标准盒模型的 Content 区域就是我们设置的宽、高大小。

在 CSS 中元素的大小和位置是由 Containing Block(包含块) 决定。在大多数情况下,一个元素的 Containing Block 就是离它最近的 block 级 的盒子的 Content 区域。比如我们把上面的例子再改一改:

xml 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Css Containing Block</title>
    <style>
      body {
        padding: 0;
        margin: 0;
      }
      .parent {
        height: 100px;
        width: 100px;
        background-color: red;
      }

      .child {
        width: 50%;
        height: 50%;
        background-color: yellow;
      }
    </style>
  </head>
  <body>
    <div>
      <div class="parent">
        <div class="child"></div>
      </div>
    </div>
  </body>
</html>

运行结果:

这是我们最熟悉的。接下来我们看看什么情况下 Containing Block 不是离它最近的 block 级 的盒子的 Content 区域。

Containing Block 的改变由元素的 position 属性决定。

1、position 值为 static、relative、sticky

如果 position 值为 static、relative、sticky,那么它的 Containing Block 就是离它最近的祖先块级元素的 Content 区域。或者是像 table、flex、grid 这种 formatting context。

position 默认值为 static

2、position 值为 absolute

如果 position 值为 absolute,它的 Containing Block 就是离它最近的 position 的值不是 static (也就是值为 fixed, absolute, relative 或 sticky)的祖先元素的 Padding 区域。

举个例子:

xml 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Css Containing Block</title>
    <style>
      body {
        padding: 0;
        margin: 0;
      }

      .grandparent {
        width: 300px;
        height: 300px;
        background-color: green;
        position: absolute;
        padding: 50px;
      }

      .parent {
        height: 100px;
        width: 100px;
        background-color: red;
      }

      .child {
        position: absolute;
        width: 10%;
        height: 10%;
        background-color: yellow;
      }
    </style>
  </head>
  <body>
    <div>
      <div class="grandparent">
        <div class="parent">
          <div class="child"></div>
        </div>
      </div>
    </div>
  </body>
</html>

这个例子中,div child 的 width 为 grandparent 的 (width + paddingleft + paddingright) = (300+50+50)*10%=40px,height 同理。

3、position 值为 fixed

如果 position 值为 fixed,在连续媒体的情况下 (continuous media) Containing Block 是 viewport。在分页媒体 (paged media) 下的情况下 Containing Block 是分 page area。关于连续媒体和分页媒体,我们的电脑显示屏一般是连续媒体,打印机一般是分页媒体。

连续媒体指的是那些可以无限延伸并且没有固定页面尺寸的媒体。常见的连续媒体包括计算机屏幕、投影仪、手机屏幕等。在处理连续媒体时,CSS 通常会自动将内容调整到适合媒体尺寸的布局,以便内容可以在用户设备上连续滚动或自适应显示。分页媒体指的是那些有固定页面尺寸、需要将内容分割成适合打印或显示在不同页面上的媒体。常见的分页媒体包括打印纸张、PDF 文件等。在处理分页媒体时,CSS 可以控制内容的分页、分栏和排版,以确保内容适合在每一页上显示,并提供良好的打印效果。

4、position 值为 absolute 或 fixed 的特殊情况

如果 position 值为 absolute 或 fixed,Containing Block 也可能是由满足以下条件的最近父级元素的 Padding 区域组成:

4.1 transform 或 perspective 的值不是 none 的父级元素

什么意思呢?我们把第二点中 position 值为 absolute 的例子改一下,给 parent 增加 transform: translate(20px, 20px);, 这个时候 child 的 Containing Block 就是 parent 了,width 和 height 都为 10px。

xml 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Css Containing Block</title>
    <style>
      body {
        padding: 0;
        margin: 0;
      }

      .grandparent {
        width: 300px;
        height: 300px;
        background-color: green;
        position: absolute;
        padding: 50px;
      }

      .parent {
        height: 100px;
        width: 100px;
        transform: translate(20px, 20px);
        background-color: red;
      }

      .child {
        position: absolute;
        width: 10%;
        height: 10%;
        background-color: yellow;
      }
    </style>
  </head>
  <body>
    <div>
      <div class="grandparent">
        <div class="parent">
          <div class="child"></div>
        </div>
      </div>
    </div>
  </body>
</html>

运行结果:

4.2 will-change 的值是 transform 或 perspective
4.3 filter 的值不是 none 或 will-change 的值是 filter(只在 Firefox 下生效)
4.4 contain 的值是 paint(例如:contain: paint;)
4.5 backdrop-filter 的值不是 none(例如:backdrop-filter: blur(10px);)

以上就是 Containing Block 就是最近父级元素的 Padding 区域。

总结

本文总结了作者对 Containing Block 的基本理解,帮助大家在写 CSS 布局的过程中遇到奇怪的现象进行问题排查。

参考资料

developer.mozilla.org/en-US/docs/...

developer.mozilla.org/en-US/docs/...

developer.mozilla.org/en-US/docs/...

developer.mozilla.org/en-US/docs/...

developer.mozilla.org/en-US/docs/...

相关推荐
LuHang1 小时前
从天地图切换到高德地图:一次真实的底图迁移实战
前端·vue.js·cesium
用户360055579001 小时前
Kestrel_VLLM - 27 · 寄存器常驻与融合发射:两次「少发一次」
前端
前端小万1 小时前
用"道法术器"重构你和 AI 的协作方式
前端·人工智能·程序员
鶴哥只手遮天1 小时前
Angular 22 源码级深度解析-第 06 章 模板指令全解:`ɵɵelementStart`、`ɵɵproperty`、`ɵɵadvance` 与绑定指令
前端·开源·angular.js
像我这样帅的人丶你还1 小时前
我html生成的doc文档为何在手机文档显示不了图片?
前端·javascript
前端双越老师3 小时前
程序员 1v1 访谈系列第十期:纯前端坚持不了多久了
前端·ai编程·全栈
门思科技4 小时前
LoRaWAN 网络排障的五层漏斗:从"上不到云"到"数值不对",每一层该用什么工具证明
前端
计算机魔术师4 小时前
Cursor 官方插件商城现恶意 Claude Code 扩展,约 11 小时影响最多 5000 名开发者
前端
掘金者阿豪4 小时前
MongoDB迁移到金仓数据库:商品属性继续灵活存,订单报表交给 SQL
前端·后端
栉甜5 小时前
Vue2学习内容(上)
前端·javascript·vue.js·学习