理解 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/...

相关推荐
福兮说41 分钟前
canvas 旋转图片的六个坑:四角被裁、Math.ceil 多出 1px 黑边、JPG 角发黑、翻转方向反了
前端·javascript·图像处理·canvas
传人once2 小时前
多图片上传预览功能如何写
前端·css·html·jquery·html5
Eric.463 小时前
Wan‑Animate+MiniMax-H3 本地部署 AI 漫剧流水线:8G 显存动作迁移与动态分镜工程实战
前端·人工智能·comfyui·ai漫剧
传人once4 小时前
悬停旋转放大和位移效果如何写
javascript·css·动画
库拉镜像AI牛牛4 小时前
短剧内容自动化生产:知漫剧工作室落地教程
大数据·服务器·前端·人工智能·语音识别
律宏阔4 小时前
Flutter 列表图片内存优化:CachedNetworkImage 与 ClipRRect 的取舍
前端·flutter
行者全栈架构师4 小时前
【鸿蒙心迹】相册文搜图工程化落地:HarmonyOS 7.0 端侧 AI 检索全链路实战与 5 个踩坑解法
前端
律宏阔4 小时前
Dart 3 Record:解决 Future.wait 异构返回值的类型问题
前端·flutter
Seraphina364 小时前
DVWA(XSS Reflected/Stored High,CSRF Low)
前端·xss·csrf
默_笙5 小时前
🍔 中间件不只是打日志:四个钩子、一次短路,和自带的工具
前端·javascript