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

相关推荐
我是苏苏3 分钟前
Web开发:C#通过ProcessStartInfo动态调用执行Python脚本
java·服务器·前端
无羡仙23 分钟前
Vue插槽
前端·vue.js
用户6387994773051 小时前
每组件(Per-Component)与集中式(Centralized)i18n
前端·javascript
SsunmdayKT1 小时前
React + Ts eslint配置
前端
开始学java1 小时前
useEffect 空依赖 + 定时器 = 闭包陷阱?count 永远停在 1 的坑我踩透了
前端
zerosrat1 小时前
从零实现 React Native(2): 跨平台支持
前端·react native
狗哥哥1 小时前
🔥 Vue 3 项目深度优化之旅:从 787KB 到极致性能
前端·vue.js
青莲8431 小时前
RecyclerView 完全指南
android·前端·面试
青莲8431 小时前
Android WebView 混合开发完整指南
android·前端·面试
GIS之路1 小时前
GDAL 实现矢量数据转换处理(全)
前端