【问题标题】:CSS 3d transform doesn't work if perspective is set in the end of property如果在属性末尾设置透视,CSS 3d 变换不起作用
【发布时间】:2019-01-24 06:09:46
【问题描述】:

我发现transform 属性取决于perspective() 位置

为什么会这样? transform 的任何其他规则/限制?

虽然我觉得很奇怪,但这似乎不是一个错误,因为我能够在 Chrome/FF 中重现它

box:nth-child(1):hover {
  transform: perspective(1000px) translate3d(0, 0, -100px);
}

box:nth-child(2):hover {
  transform: translate3d(0, 0, 100px) perspective(1000px);
}

box {
  padding: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: monospace;
  transition: transform .4s;
  background: rgba(255, 0, 0, 0.3);
  margin: 20px;
  font-size: 12px;
  perspective: 1000px;
  cursor: pointer;
}

box:nth-child(2) {
  background: rgba(0, 0, 255, 0.3);
}
<box>
  transform: perspective(1000px) translate3d(0,0,100px);
</box>
<box>
  transform: translate3d(0,0,100px) perspective(1000px);
</box>

【问题讨论】:

  • 浏览器通常没有 z 维信息(为什么需要?)。一旦不告诉浏览器元素的z位置,怎么做3维平移?
  • @MatrixTai 了解一下 transform3d 你就会明白
  • @TemaniAfif ,我的意思是 OP 必须首先声明透视图,它初始化 3d 空间。这只是一个反问。
  • @godblessstrawberry 在这种情况下也很重要...颠倒顺序并且您希望获得相同的结果,仅在某些特定情况下您才有相同的结果

标签: css css-transforms


【解决方案1】:

虽然另一个答案已经非常清楚地说明了perspective() 的工作原理。但我想让我更具体一点。

box:nth-child(1):hover {
  transform: perspective(1000px) translate3d(0, 0, 100px);
}

box:nth-child(2):hover {
  transform: translate3d(0, 0, 100px) perspective(1000px);
}

box:nth-child(3):hover {
  transform: rotate3d(1, 0, 0, 45deg) perspective(1000px) translate3d(0, 0, 100px);
}

box:nth-child(4):hover {
  transform: rotate3d(1, 0, 0, 45deg) translate3d(0, 0, 100px) perspective(1000px);
}

box:nth-child(5):hover {
  transform: rotate3d(1, 0, 0, 45deg) translate3d(0, 0, 100px);
}

box:nth-child(6):hover {
  transform: translate3d(0, 0, 100px) rotate3d(1, 0, 0, 45deg);
}

box:nth-child(7):hover {
  transform: perspective(1000px) rotate3d(1, 0, 0, 45deg) translate3d(0, 0, 100px);
}

box:nth-child(8):hover {
  transform: perspective(1000px) translate3d(0, 0, 100px) rotate3d(1, 0, 0, 45deg);
}

box {
  padding: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: monospace;
  transition: transform .4s;
  background: rgba(255, 0, 0, 0.3);
  margin: 20px;
  font-size: 12px;
  perspective: 1000px;
  cursor: pointer;
}

box:nth-child(even) {
  background: rgba(0, 0, 255, 0.3);
}
<box>
  1. transform: perspective(1000px) translate3d(0,0,100px);
</box>
<box>
  2. transform: translate3d(0,0,100px) perspective(1000px);
</box>
<box>
  3. transform: rotate3d(1,0,0,45deg) perspective(1000px) translate3d(0, 0, 100px);
</box>
<box>
  4. transform: rotate3d(1,0,0,45deg) translate3d(0, 0, 100px) perspective(1000px);
</box>
<box>
  5. transform: rotate3d(1,0,0,45deg) translate3d(0, 0, 100px);
</box>
<box>
  6. transform: translate3d(0, 0, 100px) rotate3d(1,0,0,45deg);
</box>
<box>
  7. perspective(1000px) rotate3d(1,0,0,45deg) translate3d(0, 0, 100px);
</box>
<box>
  8. perspective(1000px) translate3d(0, 0, 100px) rotate3d(1,0,0,45deg);
</box>

首先,例如 1 和 2。很明显地显示了 perspective() 如何为 translate3d 工作。

但是这是否意味着没有perspective()translate3d 就没用了?

没有。正如我在第一个命令中提到的。

不告诉浏览器元素的z位置,怎么做3维平移?


但是,二维呢?

看看示例 3 和 5。它们的行为完全不同。

为什么?因为在您进行旋转之后,它的 z 维度不再是您的窗口的 z 维度。块向上移动 100 * cos(45) = 50px

因此,5 和 6 的工作方式完全不同,rotate3d(1,0,0,45deg)translate3d(0, 0, 100px) 之间的顺序确实有所不同。

对于 7 和 8,当 z-index 也可用于元素时更为明显。确实有区别。

【讨论】:

  • 将鼠标悬停在元素上很痛苦:p
  • @TemaniAfif,哈哈,是的,因为在这些情况下元素向上移动。
【解决方案2】:

在这两种情况下,您都应该首先创建perspective。如果你在最后添加它,将首先进行翻译而不考虑视角。

如果我们参考specification,我们可以看到转换矩阵是如何计算的:

变换矩阵是根据变换和 transform-origin 属性如下:

  1. 从单位矩阵开始。

  2. 通过transform-origin的计算X和Y平移

  3. 乘以变换属性中的每个变换函数 从左到右

  4. 按转换原点的求反后的 X 和 Y 值进行转换

正如您在第 (3) 步中看到的那样,它是从从左到右(这是另一个问题,您可以从中获取更多信息并了解为什么顺序很重要:Simulating transform-origin using translate

在要转换的元素中使用perspective 属性也没有用。

box:nth-child(1):hover {
  transform: perspective(1000px) translate3d(0, 0, -100px);
}

box:nth-child(2):hover {
  transform: perspective(1000px) translate3d(0, 0, 100px);
}

box {
  padding: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: monospace;
  transition: transform .4s;
  background: rgba(255, 0, 0, 0.3);
  margin: 20px;
  /*perspective: 1000px;*/
  font-size: 12px;
  cursor: pointer;
}

box:nth-child(2) {
  background: rgba(0, 0, 255, 0.3);
}
<box>
  transform: perspective(1000px) translate3d(0,0,100px);
</box>
<box>
  transform:  perspective(1000px) translate3d(0,0,100px);
</box>

为避免与顺序混淆,您可以在父元素中声明透视,但您需要注意原点,因为它不会相同:

box:nth-child(1):hover {
  transform:translate3d(0, 0, -100px);
}

box:nth-child(2):hover {
  transform:translate3d(0, 0, 100px);
}
body {
  perspective:1000px;
}
box {
  padding: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: monospace;
  transition: transform .4s;
  background: rgba(255, 0, 0, 0.3);
  margin: 20px;
  font-size: 12px;
  cursor: pointer;
}

box:nth-child(2) {
  background: rgba(0, 0, 255, 0.3);
}
<box>
  transform: perspective(1000px) translate3d(0,0,100px);
</box>
<box>
  transform:  perspective(1000px) translate3d(0,0,100px);
</box>

【讨论】:

  • 我不明白的东西。为什么要向 body 声明透视图,因为它已经为 box 元素声明了?
  • @PIIANTOM 我将声明从盒子移到正文
  • @PIIANTOM 我明白了你的意思,如果你谈论的是盒子内的透视声明而不是变换内的 [我没有注意到] 它在这两种情况下都没用,我把它删除了......元素的声明透视图只影响转换后的子元素而不影响元素
猜你喜欢
  • 2019-11-12
  • 1970-01-01
  • 2013-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-02
  • 2012-11-07
  • 1970-01-01
相关资源
最近更新 更多