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

心不动则不痛 提交于 2021-01-27 23:33:18

问题


I have two boxes with 3d transformation (rotationY). Each have almost the same values, one perspective looks fine, the other kinda wrong but still have some correct perspective.

The first box at the top side does not protrude, but it have a perspective view yet. Also the 3° the container is 200% bigger

The second box do a beautiful 3d effect.

Here I made the example of what I'm trying to explain.

$(".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>

I think something is working wrong, but can't figure it out why. Can someone explain me why it's behaving like that?


回答1:


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

No they don't have the same values. One is using position:absolute and the the other one position:relative and this make a big difference. If you inspect the god element you will notice that its height is 0 when using the position:absolute (the first case) which is creating the issue.

Here is a simplified code to better show your issue:

.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>

For a more accurate explanation we need to refer 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.

Then we can see the math part:

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

The trick is within the steps (1)(4) related to perspective-origin. If we check the definition we can read:

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

Note the reference box which is the key here because this is the variable in out case (the god element). If we add to this the fact that the default value is 50% 50% we get our answer:

<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.


Now we have all the information to understand what is happening. In the first case where the element has 0 height, the origin is on the top center (we only consider 50% of the width) while in the second case the origin is the center since our element has a height different from 0 and more precisely a height equal to the one of the transformed element which give us a perfect result.

If we change the perspective-origin and we consider pixel values we will have the same result for both:

.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>

To conclude, the default value of perspective-origin is 50% 50% and percentage is based on the size of the element where we apply the perspective. It's now clear that if the size is changed the origin will no more be the same which will logically give us a different rendring.

To avoid this we either set a pixel value for the origin OR we consider the use of perspective() directly on the concerned element (the one we want to transform) and in this case we are sure the result will be the same since both elements are the same:

.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>

You should note in the above that perspective-origin is irrelevant and the transform-origin with define the origin since we are using the transform-function version of perspective.

Related questions:

perspective and translateZ moves diagonally

How to calculate angle of rotation to make width fit desired size in perspective mode?

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



来源:https://stackoverflow.com/questions/63026056/why-perspective-isnt-giving-the-same-result-when-some-styles-are-updated

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!