Creating 3D card objects using css

Creating 3D card objects is a good way to get started with 3D transform. But once you’ve mastered them, you’ll be hungry to push it further and create some true 3D objects: prisms. We’ll start out by making a cube.

The markup for the cube is similar to the card. This time we need 6 child elements for all 6 faces of the cube.

<div class="stage" style="width: 120px; height: 120px;">
<div class="spinner"> 
<div class="phase1" style="background-color:#f4105b; color:#FFF">1</div>
<div class="phase2" style="background-color:#17c3f4; color:#FFF">2</div>
<div class="phase3" style="background-color:#b817f4; color:#FFF">3</div>
<div class="phase4" style="background-color:#0dd25c; color:#FFF">4</div>
<div class="phase5" style="background-color:#f0c602; color:#FFF">5</div>
<div class="phase6" style="background-color:#ee6b02; color:#FFF">6</div>
</div>
</div>

Basic position and size styles set the 6 faces on top of one another in the container.

@-webkit-keyframes spincube {
  from,to  { }
  16%      { -webkit-transform: rotateY(-90deg);  }
  33%      { -webkit-transform: rotateY(-90deg) rotateZ(90deg); }
  50%      { -webkit-transform: rotateY(-180deg) rotateZ(90deg); }
  66%      { -webkit-transform: rotateY(90deg) rotateX(90deg);  }
  83%      { -webkit-transform: rotateX(90deg); }
}
@-moz-keyframes spincube {
  from,to  { }
  16%      { -moz-transform: rotateY(-90deg);  }
  33%      { -moz-transform: rotateY(-90deg) rotateZ(90deg); }
  50%      { -moz-transform: rotateY(-180deg) rotateZ(90deg); }
  66%      { -moz-transform: rotateY(90deg) rotateX(90deg);  }
  83%      { -moz-transform: rotateX(90deg); }
}
-ms-keyframes spincube {
  from,to  { }
  16%      { -ms-transform: rotateY(-90deg);  }
  33%      { -ms-transform: rotateY(-90deg) rotateZ(90deg); }
  50%      { -ms-transform: rotateY(-180deg) rotateZ(90deg); }
  66%      { -ms-transform: rotateY(90deg) rotateX(90deg);  }
  83%      { -ms-transform: rotateX(90deg); }
}

.spinner {
  -webkit-animation-name: spincube;
  -webkit-animation-timing-function: ease-in-out;
  -webkit-animation-iteration-count: infinite;
  -webkit-animation-duration: 12s;
  -webkit-transform-style: preserve-3d;
  -webkit-transform-origin: 60px 60px 0;
  -moz-animation-name: spincube;
  -moz-animation-timing-function: ease-in-out;
  -moz-animation-iteration-count: infinite;
  -moz-animation-duration: 12s;
  -moz-transform-style: preserve-3d;
  -moz-transform-origin: 60px 60px 0;
  -ms-animation-name: spincube;
  -ms-animation-timing-function: ease-in-out;
  -ms-animation-iteration-count: infinite;
  -ms-animation-duration: 12s;
  -ms-transform-style: preserve-3d;
  -ms-transform-origin: 60px 60px 0;
}

.spinner div {
  position: absolute;
  width: 120px;
  height: 120px;
  border: 1px solid #ccc;
  background: rgba(255,255,255,0.8);
  box-shadow: inset 0 0 20px rgba(0,0,0,0.2);
  text-align: center;
  font-size: 100px;
}

.spinner .phase1 {
  -webkit-transform: translateZ(60px);
  -moz-transform: translateZ(60px);
  -moz-transform: translateZ(60px);
}
.spinner .phase2 {
  -webkit-transform: rotateY(90deg) translateZ(60px);
  -moz-transform: rotateY(90deg) translateZ(60px);
  -ms-transform: rotateY(90deg) translateZ(60px);
}
.spinner .phase3 {
  -webkit-transform: rotateY(90deg) rotateX(90deg) translateZ(60px);
  -moz-transform: rotateY(90deg) rotateX(90deg) translateZ(60px);
  -ms-transform: rotateY(90deg) rotateX(90deg) translateZ(60px);
}
.spinner .phase4 {
  -webkit-transform: rotateY(180deg) rotateZ(90deg) translateZ(60px);
  -moz-transform: rotateY(180deg) rotateZ(90deg) translateZ(60px);
  -ms-transform: rotateY(180deg) rotateZ(90deg) translateZ(60px);
}
.spinner .phase5 {
  -webkit-transform: rotateY(-90deg) rotateZ(90deg) translateZ(60px);
  -moz-transform: rotateY(-90deg) rotateZ(90deg) translateZ(60px);
  -ms-transform: rotateY(-90deg) rotateZ(90deg) translateZ(60px);
}
.spinner .phase6 {
  -webkit-transform: rotateX(-90deg) translateZ(60px);
  -moz-transform: rotateX(-90deg) translateZ(60px);
  -ms-transform: rotateX(-90deg) translateZ(60px);
}

With the card, we only had to rotate its back face. The cube, however, requires that 5 of the 6 faces to be rotated. Faces 1 and 2 will be the front and back. Faces 3 and 4 will be the sides. Faces 5 and 6 will be the top and bottom.

.cubespinner .face5 {
  -webkit-transform: rotateY(-90deg) rotateZ(90deg) translateZ(60px);
  -moz-transform: rotateY(-90deg) rotateZ(90deg) translateZ(60px);
  -ms-transform: rotateY(-90deg) rotateZ(90deg) translateZ(60px);
}
.cubespinner .face6 {
  -webkit-transform: rotateX(-90deg) translateZ(60px);
  -moz-transform: rotateX(-90deg) translateZ(60px);
  -ms-transform: rotateX(-90deg) translateZ(60px);
}
.cubespinner .face3 {
  -webkit-transform: rotateY(90deg) rotateX(90deg) translateZ(60px);
  -moz-transform: rotateY(90deg) rotateX(90deg) translateZ(60px);
  -ms-transform: rotateY(90deg) rotateX(90deg) translateZ(60px);
}
.cubespinner .face4 {
  -webkit-transform: rotateY(180deg) rotateZ(90deg) translateZ(60px);
  -moz-transform: rotateY(180deg) rotateZ(90deg) translateZ(60px);
  -ms-transform: rotateY(180deg) rotateZ(90deg) translateZ(60px);
}

We could remove the #cube .front style declaration, as this transform has no effect, but let’s leave it in to keep our code consistent.

Now each face is rotated, and only the front face is visible. The 4 side faces are all perpendicular to the viewer, so they appear invisible. To push them out to their appropriate sides, they need to be translated out from the center of their positions. Each side of the cube is 200px wide. From the cube’s center they’ll need to be translated out half that distance, 100px.

@-webkit-keyframes spincube {
  from,to  { }
  16%      { -webkit-transform: rotateY(-90deg);  }
  33%      { -webkit-transform: rotateY(-90deg) rotateZ(90deg); }
  50%      { -webkit-transform: rotateY(-180deg) rotateZ(90deg); }
  66%      { -webkit-transform: rotateY(90deg) rotateX(90deg);  }
  83%      { -webkit-transform: rotateX(90deg); }
}
@-moz-keyframes spincube {
  from,to  { }
  16%      { -moz-transform: rotateY(-90deg);  }
  33%      { -moz-transform: rotateY(-90deg) rotateZ(90deg); }
  50%      { -moz-transform: rotateY(-180deg) rotateZ(90deg); }
  66%      { -moz-transform: rotateY(90deg) rotateX(90deg);  }
  83%      { -moz-transform: rotateX(90deg); }
}
-ms-keyframes spincube {
  from,to  { }
  16%      { -ms-transform: rotateY(-90deg);  }
  33%      { -ms-transform: rotateY(-90deg) rotateZ(90deg); }
  50%      { -ms-transform: rotateY(-180deg) rotateZ(90deg); }
  66%      { -ms-transform: rotateY(90deg) rotateX(90deg);  }
  83%      { -ms-transform: rotateX(90deg); }
}

Note here that the translateZ function comes after the rotate. The order of transform functions is important. Take a moment and soak this in. Each face is first rotated towards its position, then translated outward in a separate vector.

We have a working cube, but we’re not done yet.

Returning to the Z origin plane

For the sake of our users, our 3D transforms should not distort the interface when the active panel is at its resting position. But once we start pushing elements out of the Z origin plane, distortion is inevitable.

In order to keep 3D transforms snappy, Safari composites the element then applies the transform. Consequently, anti-aliasing on text will remain whatever it was before the transform was applied. When transformed forward in 3D space, significant pixelation can occur.

To expose any face of the cube, we’ll need a style that rotates the cube to expose any face. The transform is the opposite of the corresponding face. We toggle the necessary class on the #box to apply the appropriate transform.

#cube.show-front  { transform: translateZ( -100px ) rotateY(    0deg ); }
#cube.show-back   { transform: translateZ( -100px ) rotateX( -180deg ); }
#cube.show-right  { transform: translateZ( -100px ) rotateY(  -90deg ); }
#cube.show-left   { transform: translateZ( -100px ) rotateY(   90deg ); }
#cube.show-top    { transform: translateZ( -100px ) rotateX(  -90deg ); }
#cube.show-bottom { transform: translateZ( -100px ) rotateX(   90deg ); }

Notice how the order of the transform functions has reversed. First we push the object back withtranslateZ, then we rotate it.

Finishing up, we can add a transition to animate the rotation between states.

#cube { transition: transform 1s; }

Let's Think together, Say Something !