为什么在更新某些样式时透视不会给出相同的结果?

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

我有两个带 3d 变换(rotationY)的盒子。每个人的价值观几乎相同,一个观点看起来不错,另一个观点有点错误,但仍然有一些正确的观点。

最上面的第一个盒子没有凸出,但是还是有透视图的。另外 3° 容器大 200%

第二个盒子做了漂亮的 3d 效果。

这里我举个例子说明一下。

$(".eye").on('click', function () {
            $( '.man' ).toggleClass('open');      
        })
* {  padding: 0;  margin: 0; }
        .eye { padding: 6px 8px; }
        .universe {
            background: rgb(0 0 255 / 0.3);
            position: absolute;
            height: 100%;
            width: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        .dark {
          background: rgb(0 255 0 / 0.3);
          width: 25%;
          height: 25%;
        }
        .god {
          background: rgb(255 0 0 / 0.3);
          transform-style: preserve-3d;
          transform: perspective(800px);
        }
        .man {
          position: absolute;
          transform-origin: top left;
          transition: 1s all linear;
        } 
        .man.open {
          transform: rotateY(-60deg); 
        }
        .life {
          background: rgb(255 255 0 / 0.36);
          width: 25vw;
          height: 25vh;              
        }
        .no.god {
          height: 100%;
        }
        .no.man {
          position: relative; 
        }
        .yes.god {
          height: 200%;
        }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="universe">
              <div class="dark">
                <div class="god">
                  <div class="man">
                    <div class="life">Nothing happens until something moves.</div>
                  </div>
                </div>
              </div>
              <button class="eye"> OPEN </button>
              <div class="dark no">
                <div class="god no">
                  <div class="man no">
                    <div class="life no">Nothing happens until something moves.</div>
                  </div>
                </div>
              </div>
             <button class="eye"> OPEN </button>
              <div class="dark yes">
               <div class="god yes">
                <div class="man yes">
                  <div class="life yes">Nothing happens until something moves.</div>
                </div>
               </div>
              </div>
            </div>

我认为有些地方出了问题,但无法弄清楚原因。有人可以向我解释为什么会这样吗?

Each have almost the same values, one perspective looks fine,

不,它们没有相同的值。一个使用 position:absolute,另一个使用 position:relative,这有很大的不同。如果您检查 god 元素,您会注意到在使用 position:absolute(第一种情况)时它的高度为 0,这是造成问题的原因。

这是一个简化的代码,可以更好地显示您的问题:

.box {
  display: inline-block;
  vertical-align:top;
  width: 100px;
  perspective: 200px;
  position: relative;
  margin: 20px;
  background:blue;
}

.box>div {
  position: relative;
  padding: 10px;
  background: red;
  color: #fff;
  transition: 1s all linear;
  transform-origin: top left;
}

body:hover .box > div {
  transform: rotateY(-40deg);
}
<div class="box">
  <div>Some text here</div>
</div>
<div class="box">
  <div style="position:absolute;">Some text here</div>
</div>

更准确的解释需要参考to the specification

Perspective can be used to add a feeling of depth to a scene by making elements higher on the Z axis (closer to the viewer) appear larger, and those further away to appear smaller. The scaling is proportional to d/(d − Z) where d, the value of perspective, is the distance from the drawing plane to the the assumed position of the viewer’s eye.

Second, the perspective and perspective-origin properties can be applied to an element to influence the rendering of its 3d-transformed children, giving them a shared perspective that provides the impression of them living in the same three-dimensional scene.

然后我们可以看到数学部分:

The perspective matrix is computed as follows:

  1. Start with the identity matrix.

  2. Translate by the computed X and Y values of perspective-origin

  3. Multiply by the matrix that would be obtained from the perspective() transform function, where the length is provided by the value of the perspective property

  4. Translate by the negated computed X and Y values of perspective-origin

诀窍在与 perspective-origin 相关的步骤 (1)(4) 中。如果我们检查定义,我们可以阅读:

The values for perspective-origin represent an offset of the perspective origin from the top left corner of the reference box.

请注意 引用框 这是这里的关键,因为这是 out case 中的变量(god 元素)。如果我们添加默认值为 50% 50% 的事实,我们会得到答案:

<percentage>

A percentage for the horizontal perspective offset is relative to the width of the reference box. A percentage for the vertical offset is relative to height of the reference box. The value for the horizontal and vertical offset represent an offset from the top left corner of the reference box.


现在我们拥有了解正在发生的事情的所有信息。在第一种情况下,元素的高度为 0,原点位于顶部中心(我们只考虑宽度的 50%),而在第二种情况下,原点是中心,因为我们的元素的高度不同于 0更准确地说,高度等于为我们提供完美结果的转换元素之一。

如果我们更改 perspective-origin 并考虑像素值,我们将得到相同的结果:

.box {
  display: inline-block;
  vertical-align:top;
  width: 100px;
  perspective: 200px;
  perspective-origin:50px 30px;
  position: relative;
  margin: 20px;
  background:blue;
}

.box>div {
  position: relative;
  padding: 10px;
  background: red;
  color: #fff;
  transition: 1s all linear;
  transform-origin: top left;
}

body:hover .box > div {
  transform: rotateY(-40deg);
}
<div class="box">
  <div>Some text here</div>
</div>
<div class="box">
  <div style="position:absolute;">Some text here</div>
</div>

总而言之,perspective-origin 的默认值为 50% 50%,百分比基于我们应用透视图的元素的大小。现在很清楚,如果更改大小,原点将不再相同,这在逻辑上会给我们一个不同的渲染。

为了避免这种情况,我们要么为原点设置一个像素值,要么我们考虑直接在相关元素(我们要转换的元素)上使用 perspective(),在这种情况下我们确定结果将相同,因为两个元素相同:

.box {
  display: inline-block;
  vertical-align:top;
  width: 100px;
  position: relative;
  margin: 20px;
  background:blue;
}

.box>div {
  position: relative;
  padding: 10px;
  background: red;
  color: #fff;
  transition: 1s all linear;
  transform-origin: center left;
  transform: perspective(200px) rotateY(0);
}

body:hover .box > div {
  transform: perspective(200px) rotateY(-40deg);
}
<div class="box">
  <div>Some text here</div>
</div>
<div class="box">
  <div style="position:absolute;">Some text here</div>
</div>

<div class="box" style="height:500px;">
  <div style="position:absolute;">Some text here</div>
</div>

你应该注意到上面的 perspective-origin 是无关紧要的,transform-origin 定义了原点,因为我们使用的是透视的变换函数版本。

相关问题: