如果父元素有自己的转换,为什么 CSS translateZ 会被忽略?

问题描述

谁能解释这种行为?

我有三个嵌套元素:容器 div、子容器 div 和“形状/图像”div标记如下:

<html>
  <div class="container">
    <div class="subcontainer">
      <div class="shape"></div>
    </div>
  </div>
</html>

当我将 transform: translateZ() 应用到形状时,显然只有在其中一位父母应用了一些 perspective 时它才会起作用。它不一定是直接父级,它可以是父级的父级 div(容器)。当容器具有 perspective 时,形状会在 z 方向精细移动。但是,当子容器(父容器)在 transform 中包含除 unset 之外的内容时,形状中的 translateZ() 将被完全忽略。当然,将 perspective 应用于直接父级会使形状中的 translateZ() 起作用,但我想了解父级 transform 中的内容阻止了 perspective形状:

以下作品:

.container{
  perspective: 1000px;
}

.subcontainer{
  transform: unset;     // <- or if this is not present at all
}

.shape{
  transform: translateZ(300px);
}

以下不起作用:

.container{
  perspective: 1000px;
}

.subcontainer{
  transform: scale(1.001);
}

.shape{
  transform: translateZ(300px);    // <- this is fully ignored
}

这是 codepen 中的 this example

编辑: 在许多文档中,我读到 perspective 必须是在父元素中设置的属性。但是 MDN 似乎表明它实际上可以在预期元素本身中设置,在 transform 规则内。那么,父级中的 perspective: 500px 是否等同于子级中的 transform: perspective(500px)

解决方法

来自the specification:

默认情况下,转换后的元素不创建 3D 渲染上下文,而是创建其内容的扁平化表示。但是,由于构建共享公共 3 维空间的变换对象的层次结构很有用,因此可以通过为 preserve-3d 属性指定 transform-style 值来覆盖这种展平行为。 这允许转换后的元素的后代共享相同的 3D 渲染上下文

因此只需将 transform-style:preserve-3d 添加到子容器元素,祖父的观点就会得到尊重:

.container{
  background: #f4f7be;
  height: 100vh;
  width: 100vw;
  display: flex;
  justify-content: center;
  align-items: center;
  perspective: 1000px;
}

.subcontainer{
  background: #baf7f6;
  width: 70%;
  height: 70%;
  display: flex;
  justify-content: center;
  align-items: center;
  transform: scale(1.001);
  transform-style:preserve-3d;
}

.shape{
  background: #555;
  width: 40%;
  height: 50%;
  clip-path: polygon(50% 0%,0% 100%,100% 100%);
  transform: translateZ(300px);
}
<html>
  <div class="container">
    <div class="subcontainer">
      <div class="shape"></div>
    </div>
  </div>
</html>


那么,父级中的透视:500px 是否等同于子级中的变换:透视(500px)?

不完全等效,因为您需要考虑其他因素,例如父维度、变换原点、透视原点等

一个简单的例子:

.box {
  padding: 20px;
  border: 1px solid;
}

.box>div {
  width: 100px;
  height: 100px;
  background: red;
}
<div class="box" style="perspective:100px;">
  <div style="transform:translateZ(10px);"></div>
</div>

<div class="box">
  <div style="transform:perspective(100px) translateZ(10px);"></div>
</div>

区别在于起源。在第一种情况下,透视将使用父级的中心作为原点(因为 perspective-origin 默认为中心)。在第二种情况下,元素的中心将用作原点(因为 transform-origin 默认为中心)

更多细节和示例的相关问题:

perspective and translateZ moves diagonally

Why perspective isn't giving the same result when some styles are updated?

CSS 3d transform doesn't work if perspective is set in the end of property