Search code examples
htmlcsscss-animationscss-transforms

Skew an HTML element in the Z direction


Below is the base "un-skewed" element we want to skew in both the Z and X direction to create a diagonal skew.

* {
  box-sizing: border-box;
  transform-style: preserve-3d;
  margin: 0; padding: 0;
}
html, body {
  height: 100%;
}
body {
  perspective: 30rem;
}
body, div, span {
  display: flex;
  justify-content: center;
  align-items: center;
}
section > div > div {
  transform: scaleX( 0.5 ) scaleZ( 0.5 );
}
div div:nth-of-type( 2 ) {
  transform: rotateY( 180deg ) rotateZ( 90deg );
}
span {
  position: absolute;
  box-shadow: 0rem 0rem 0rem 0.5rem #444 inset;
  width: 10rem;
  height: 10rem;
  background-color: rgba( 200,200,200,0.25 );
}
span:nth-of-type( 1 ) { transform: translateZ( 5rem ); }
span:nth-of-type( 2 ) { transform: rotateY( 90deg ) translateZ( 5rem ); }
span:nth-of-type( 3 ) { transform: rotateY( -90deg ) translateZ( 5rem ); }
<style>
  .rotate_y, .rotate_x {
    animation-name: rotateY;
    animation-duration: 6s;
    animation-timing-function: linear;
    animation-iteration-count: infinite;
  }
  @keyframes rotateY {
    0% { transform: rotateY( 0deg ); }
    100% { transform: rotateY( 360deg ); }  
  }
  .rotate_x {
    animation-name: rotateX;
  }
  @keyframes rotateX {
    0% { transform: rotateX( 0deg ); }
    100% { transform: rotateX( 360deg ); }  
  }
</style>

<section class='rotate_y'>
  <div class='rotate_x'>
    <div>
      <div> <span></span><span></span><span></span> </div>
      <div> <span></span><span></span><span></span> </div> 
    </div>
  </div>
</section>

Adding transform: skewX( 45deg ) to body section > div > div in the HTML window works as expected:

* {
  box-sizing: border-box;
  transform-style: preserve-3d;
  margin: 0; padding: 0;
}
html, body {
  height: 100%;
}
body {
  perspective: 30rem;
}
body, div, span {
  display: flex;
  justify-content: center;
  align-items: center;
}
section > div > div {
  transform: scaleX( 0.5 ) scaleZ( 0.5 );
}
div div:nth-of-type( 2 ) {
  transform: rotateY( 180deg ) rotateZ( 90deg );
}
span {
  position: absolute;
  box-shadow: 0rem 0rem 0rem 0.5rem #444 inset;
  width: 10rem;
  height: 10rem;
  background-color: rgba( 200,200,200,0.25 );
}
span:nth-of-type( 1 ) { transform: translateZ( 5rem ); }
span:nth-of-type( 2 ) { transform: rotateY( 90deg ) translateZ( 5rem ); }
span:nth-of-type( 3 ) { transform: rotateY( -90deg ) translateZ( 5rem ); }
<style>
  .rotate_y, .rotate_x {
    animation-name: rotateY;
    animation-duration: 6s;
    animation-timing-function: linear;
    animation-iteration-count: infinite;
  }
  @keyframes rotateY {
    0% { transform: rotateY( 0deg ); }
    100% { transform: rotateY( 360deg ); }  
  }
  .rotate_x {
    animation-name: rotateX;
  }
  @keyframes rotateX {
    0% { transform: rotateX( 0deg ); }
    100% { transform: rotateX( 360deg ); }  
  }
  
  /* skew in the X direction added */
  body section > div > div {
    transform: scaleX( 0.5 ) scaleZ( 0.5 ) skewX( 45deg );
  }
</style>

<section class='rotate_y'>
  <div class='rotate_x'>
    <div>
      <div> <span></span><span></span><span></span> </div>
      <div> <span></span><span></span><span></span> </div> 
    </div>
  </div>
</section>

transform: skewX( 45deg ) and transform: skewY( 45deg ) work perfectly. However adding transform: skewZ( 45deg ) does not.

Is skewing in the Z direction a part of the CSS spec? And if not what is a good workaround?

Below is an example snippet of what happens when I set skewZ(). ( it nullifies all transform properties as if it's an invalid CSS rule. )

* {
  box-sizing: border-box;
  transform-style: preserve-3d;
  margin: 0; padding: 0;
}
html, body {
  height: 100%;
}
body {
  perspective: 30rem;
}
body, div, span {
  display: flex;
  justify-content: center;
  align-items: center;
}
section > div > div {
  transform: scaleX( 0.5 ) scaleZ( 0.5 );
}
div div:nth-of-type( 2 ) {
  transform: rotateY( 180deg ) rotateZ( 90deg );
}
span {
  position: absolute;
  box-shadow: 0rem 0rem 0rem 0.5rem #444 inset;
  width: 10rem;
  height: 10rem;
  background-color: rgba( 200,200,200,0.25 );
}
span:nth-of-type( 1 ) { transform: translateZ( 5rem ); }
span:nth-of-type( 2 ) { transform: rotateY( 90deg ) translateZ( 5rem ); }
span:nth-of-type( 3 ) { transform: rotateY( -90deg ) translateZ( 5rem ); }
<style>
  .rotate_y, .rotate_x {
    animation-name: rotateY;
    animation-duration: 6s;
    animation-timing-function: linear;
    animation-iteration-count: infinite;
  }
  @keyframes rotateY {
    0% { transform: rotateY( 0deg ); }
    100% { transform: rotateY( 360deg ); }  
  }
  .rotate_x {
    animation-name: rotateX;
  }
  @keyframes rotateX {
    0% { transform: rotateX( 0deg ); }
    100% { transform: rotateX( 360deg ); }  
  }
  
  /* skewing in the Z direction doesn't register */
  body section > div > div {
    transform: scaleX( 0.5 ) scaleZ( 0.5 ) skewX( 45deg ) skewZ( 45deg );
  }
</style>

<section class='rotate_y'>
  <div class='rotate_x'>
    <div>
      <div> <span></span><span></span><span></span> </div>
      <div> <span></span><span></span><span></span> </div> 
    </div>
  </div>
</section>

The desired result here is for the html element in question to be skewed both in the Z and X direction simultaneously.


Solution

  • Actually, there is not the possibility to set simply a skewZ, because it is harder than that.

    The skew that you already know, are 2D transforms. What they really are, is skewX (for the Y axis), and skewY (for the X axis).

    When going 3D, you would have

    • skewX for Y
    • skewX for Z
    • skewY for X
    • skewY for Z
    • skewZ for X
    • skewZ for Y

    Not so easy !

    There are 2 ways to get some skewZ.

    First, using a rotation, as you already commented. Just rememeber to unset it:

    transform: rotateX(90deg) skewX(10deg) rotateX(-90deg)
    

    The other one is to use a transform matrix . This is a matrix with the clasicals skews

    1          skewY      0        0
    skewX         1       0        0
    0             0       1        0
    0             0       0        1 
    

    And this is a matrix with the Z skews

    1             0      skewZ/x        0
    0             1      skewZ/y        0
    0             0       1             0
    0             0       0             1