3D Transforms in CSS: perspective, rotateX, rotateY, and translateZ
Introduction to 3D Space in CSS
CSS transforms can move beyond the flat 2D plane into three-dimensional space. While 2D transforms (covered in the 2D Transforms article) work with X and Y axes, 3D transforms add the Z axis — depth moving toward and away from the viewer.
The perspective Property
perspective is the foundation of 3D transforms. It defines how far the viewer is from the Z=0 plane, creating the illusion of depth:
.container {
perspective: 1000px;
}
.card {
transform: rotateY(45deg);
}Lower vs Higher Perspective Values
/* Dramatic, close-up perspective */
.dramatic { perspective: 500px; }
/* Moderate depth */
.moderate { perspective: 1000px; }
/* Subtle, distant perspective */
.subtle { perspective: 2000px; }Lower values create more dramatic 3D effects (like viewing from up close). Higher values create subtler effects (like viewing from far away).
perspective vs transform: perspective()
/* On parent: affects all children */
.container {
perspective: 1000px;
}
/* On element: affects only that element */
.element {
transform: perspective(1000px) rotateY(45deg);
}Using perspective on a parent creates a shared vanishing point for all children — usually the desired effect for card flips and similar interactions.
perspective-origin
Controls where the viewer is looking from (the vanishing point):
.container {
perspective: 1000px;
perspective-origin: 50% 50%; /* Center (default) */
}
/* View from top-left */
.top-left {
perspective-origin: 0% 0%;
}
/* View from bottom-right */
.bottom-right {
perspective-origin: 100% 100%;
}
/* View from left side */
.left-view {
perspective-origin: 0% 50%;
}3D Rotation
rotateX() — Rotation Around Horizontal Axis
Like a door swinging open toward or away from you:
.flip-vertical {
transform: rotateX(45deg); /* Tips backward */
transform: rotateX(-45deg); /* Tips forward */
transform: rotateX(180deg); /* Flipped upside-down, facing away */
}rotateY() — Rotation Around Vertical Axis
Like a revolving door:
.flip-horizontal {
transform: rotateY(45deg); /* Turns right */
transform: rotateY(-45deg); /* Turns left */
transform: rotateY(180deg); /* Fully turned around */
}rotateZ() — Rotation Around Depth Axis
Same as 2D rotate() — spins like a wheel:
.spin {
transform: rotateZ(45deg);
/* Identical to: transform: rotate(45deg); */
}rotate3d() — Combined Rotation
/* rotate3d(x, y, z, angle) */
.complex-rotation {
transform: rotate3d(1, 1, 0, 45deg);
}3D Translation
translateZ() — Moving in Depth
.closer {
transform: translateZ(100px); /* Moves toward viewer */
}
.farther {
transform: translateZ(-100px); /* Moves away from viewer */
}translateZ requires perspective to be visible.
translate3d() — Combined Translation
/* translate3d(x, y, z) */
.move-3d {
transform: translate3d(50px, 30px, 100px);
}transform-style: preserve-3d
By default, 3D-transformed children are flattened into the parent's plane. Use preserve-3d to maintain the 3D space:
.scene {
perspective: 1000px;
}
.cube {
transform-style: preserve-3d;
/* Children will exist in true 3D space */
}
.cube-face {
transform: rotateY(90deg) translateZ(50px);
/* Actually positioned in 3D, not flattened */
}backface-visibility
Controls whether the back of a 3D element is visible:
.card-face {
backface-visibility: hidden; /* Hide when facing away */
}
.card-face {
backface-visibility: visible; /* Show back (default) */
}Essential for card flip effects where you have separate front and back faces.
Classic Card Flip Effect
.card-container {
perspective: 1000px;
width: 300px;
height: 400px;
}
.card {
width: 100%;
height: 100%;
position: relative;
transform-style: preserve-3d;
transition: transform 0.6s;
}
.card-container:hover .card {
transform: rotateY(180deg);
}
.card-front,
.card-back {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
border-radius: 12px;
}
.card-front {
background: #3498db;
color: white;
}
.card-back {
background: #2c3e50;
color: white;
transform: rotateY(180deg);
}3D Cube
.scene {
perspective: 800px;
width: 200px;
height: 200px;
}
.cube {
width: 100%;
height: 100%;
position: relative;
transform-style: preserve-3d;
transform: translateZ(-100px) rotateX(-20deg) rotateY(30deg);
animation: rotate-cube 10s infinite linear;
}
.cube-face {
position: absolute;
width: 200px;
height: 200px;
opacity: 0.9;
border: 2px solid white;
}
.front { transform: translateZ(100px); background: #e74c3c; }
.back { transform: translateZ(-100px) rotateY(180deg); background: #3498db; }
.right { transform: translateX(100px) rotateY(90deg); background: #2ecc71; }
.left { transform: translateX(-100px) rotateY(-90deg); background: #f39c12; }
.top { transform: translateY(-100px) rotateX(90deg); background: #9b59b6; }
.bottom { transform: translateY(100px) rotateX(-90deg); background: #1abc9c; }
@keyframes rotate-cube {
from { transform: translateZ(-100px) rotateX(0deg) rotateY(0deg); }
to { transform: translateZ(-100px) rotateX(360deg) rotateY(360deg); }
}3D Button Press Effect
.button-3d {
padding: 1rem 2rem;
background: #3498db;
color: white;
border: none;
border-radius: 8px;
font-size: 1rem;
cursor: pointer;
transform: perspective(500px) rotateX(0deg);
transition: transform 0.1s ease;
}
.button-3d:hover {
transform: perspective(500px) rotateX(10deg);
}
.button-3d:active {
transform: perspective(500px) rotateX(-5deg);
}Hover Tilt Effect
.tilt-card {
transition: transform 0.3s ease;
transform-style: preserve-3d;
}
.tilt-card:hover {
transform: perspective(1000px) rotateX(5deg) rotateY(-5deg) scale(1.02);
}
/* For JS-powered dynamic tilt based on mouse position */
.tilt-dynamic {
transition: transform 0.1s ease;
}Performance Tips
- 3D transforms are GPU-accelerated and generally performant
- Avoid animating perspective itself — animate the transforms instead
- Use will-change: transform sparingly for elements that will animate
- Complex 3D scenes with many elements can be expensive
- Test on mobile devices — some older devices struggle with 3D
Key Takeaways
- perspective creates the 3D space — lower values = more dramatic
- rotateX() flips vertically, rotateY() flips horizontally
- translateZ() moves toward/away from viewer
- transform-style: preserve-3d maintains 3D space for children
- backface-visibility: hidden is essential for card flip effects
- Always set perspective on a parent container for consistent vanishing point
This builds on the 2D Transforms article and connects to CSS Transitions and Animations for creating smooth 3D motion effects.