You can do a lot with CSS transforms! In this post we'll walk through making a 3D cube.
First, let's create the markup:
<div class="container">
<div class="cube">
<div class="face top">Top</div>
<div class="face bottom">Bottom</div>
<div class="face left">Left</div>
<div class="face right">Right</div>
<div class="face front">Front</div>
<div class="face back">Back</div>
</div>
</div>
Each face of the cube is its own div
element. Let's create some initial styles:
.container {
width: 200px;
height: 200px;
perspective: 500px;
margin: 100px;
}
.cube {
position: relative;
width: 200px;
height: 200px;
transform-style: preserve-3d;
}
.face {
width: 200px;
height: 200px;
background: skyblue;
border: 2px solid black;
position: absolute;
opacity: 0.5;
display: flex;
align-items: center;
justify-content: center;
font-family: Arial, sans-serif;
font-size: 2rem;
}
We've given some styling to the cube faces and absolutely positioned them so they are all sitting on top of one another. First, we will rotate each face so that it's facing the proper direction. The next step will be to move each face out from the center to the edges of the cube.
Here is what we have so far:
We are currently looking at the cube head-on. It will be easier to visualize if we rotate our "camera" a bit. Let's add a rotate3d
transform to the cube:
.cube {
position: relative;
width: 200px;
height: 200px;
transform-style: preserve-3d;
transform: rotate3d(1, 1, 0, 45deg);
}
Now the elements are rotated at an angle, so we can see the 3D structure better:
Let's tackle the front first. Our cube is 200px by 200px by 200px. Currently all the elements are in the dead center of the cube. The front is already facing the right direction, we just need to move it out by 100px so that it is at the front edge. Let's add a new rule for the front and move it out:
.front {
transform: translateZ(100px);
}
Now the front face of the cube is in place:
Next is the back. It is already in the proper plane, but we need to rotate it 180 degrees around the y-axis so that the text is facing outwards. Like the front, we also need to move it out by 100px:
.back {
transform: translateZ(-100px) rotateY(180deg);
}
The back face is now in the proper position:
Let's do the left and right next. These need to be rotated 90 degrees around the y-axis so that they are both facing outwards on each side. The left side needs to be rotated by -90 degrees.
Then they need to be moved along the x-axis to the edges of the cube:
.left {
transform: translateX(-100px) rotateY(-90deg);
}
.right {
transform: translateX(100px) rotateY(90deg);
}
Lastly, we need to position the top and bottom. These need to be rotated 90 degrees around the x-axis so that they are facing up and down. Again, the top will need a rotation of 90 degrees and the bottom -90 degrees, so that the text direction is correct.
.top {
transform: translateY(-100px) rotateX(90deg);
}
.bottom {
transform: translateY(100px) rotateX(-90deg);
}
Looks like a cube!
To show off our new cube, let's give it a turning animation:
@keyframes turn {
from { transform: rotate3d(0, 0, 0, 0); }
to { transform: rotate3d(1, 1, 0, 360deg); }
}
.cube {
position: relative;
width: 200px;
height: 200px;
transform-style: preserve-3d;
animation: turn 5s linear infinite;
}
Lastly, we want to be mindful of accessibility. If the user has disabled animations in their operating system, let's not animate the cube but rather display it at the 45 degree angle we had before:
@media (prefers-reduced-motion: reduce) {
.cube {
animation: none;
transform: rotate3d(1, 1, 0, 45deg);
}
}
Here is the finished product in a CodePen:
Did you like this post? Learn more CSS in my upcoming book, Modern CSS!