CSS 3D Transforms: Complete Guide
What Are 3D CSS Transforms?
CSS 3D transforms extend the 2D transform property with a third axis (Z), allowing you to position, rotate, and scale elements in three-dimensional space. Combined with the perspective property, they create realistic depth effects — card flips, rotating carousels, unfolding panels — all without JavaScript or canvas.
The browser composites 3D-transformed elements on the GPU, making them inherently smooth and performant for animation.
The Z Axis and Perspective
Before 3D transforms work visually, you need perspective. Without it, Z-axis changes have no apparent depth:
.scene {
perspective: 800px;
}
.card {
transform: rotateY(45deg);
}
perspectiveon the parent defines the viewing distance. Lower values (200px) produce dramatic distortion; higher values (2000px) look nearly flat. 600–1000px is a natural range.transform: perspective()on the element itself works similarly but applies individually — each element gets its own vanishing point.
perspective-origin
Control where the viewer looks by setting perspective-origin on the parent:
.scene {
perspective: 800px;
perspective-origin: 50% 50%; /* default: center */
}
Changing this offset shifts the 3D effect as if you moved your head.
3D Transform Functions
| Function | Effect |
|---|---|
translate3d(tx, ty, tz) | Moves along all three axes |
translateZ(tz) | Moves closer or farther along Z |
rotateX(angle) | Rotates around the horizontal axis |
rotateY(angle) | Rotates around the vertical axis |
rotateZ(angle) | Rotates around the depth axis (same as 2D rotate) |
scale3d(sx, sy, sz) | Scales on all three axes |
scaleZ(sz) | Scales along Z (only visible with child content) |
.box {
transform: rotateX(30deg) rotateY(-20deg) translateZ(50px);
}
Order matters — transforms apply right-to-left, just like matrix multiplication.
Card Flip Effect
The classic card flip uses rotateY with backface-visibility:
.card-container {
perspective: 800px;
width: 300px;
height: 400px;
}
.card {
position: relative;
width: 100%;
height: 100%;
transition: transform 0.6s;
transform-style: preserve-3d;
}
.card-container:hover .card {
transform: rotateY(180deg);
}
.card-front,
.card-back {
position: absolute;
inset: 0;
backface-visibility: hidden;
}
.card-back {
transform: rotateY(180deg);
}
Key points:
transform-style: preserve-3don.cardkeeps front and back in 3D space rather than flattening them.backface-visibility: hiddenprevents seeing the reverse side bleed through during rotation.- The back face is pre-rotated
180degso it faces the viewer when the card flips.
3D Carousel
A carousel places items in a ring using rotateY and translateZ:
.carousel {
position: relative;
width: 200px;
height: 200px;
transform-style: preserve-3d;
animation: spin 12s linear infinite;
}
.carousel .face {
position: absolute;
width: 200px;
height: 200px;
}
/* 6-sided carousel: each face rotated 60deg apart, pushed out by Z */
.carousel .face:nth-child(1) { transform: rotateY(0deg) translateZ(200px); }
.carousel .face:nth-child(2) { transform: rotateY(60deg) translateZ(200px); }
.carousel .face:nth-child(3) { transform: rotateY(120deg) translateZ(200px); }
.carousel .face:nth-child(4) { transform: rotateY(180deg) translateZ(200px); }
.carousel .face:nth-child(5) { transform: rotateY(240deg) translateZ(200px); }
.carousel .face:nth-child(6) { transform: rotateY(300deg) translateZ(200px); }
@keyframes spin {
to { transform: rotateY(360deg); }
}
The translateZ value determines the carousel radius. For N faces, each rotates by 360/N degrees.
3D Cube
A cube is a carousel with top and bottom faces added via rotateX:
.cube .front { transform: translateZ(100px); }
.cube .back { transform: rotateY(180deg) translateZ(100px); }
.cube .right { transform: rotateY(90deg) translateZ(100px); }
.cube .left { transform: rotateY(-90deg) translateZ(100px); }
.cube .top { transform: rotateX(90deg) translateZ(100px); }
.cube .bottom { transform: rotateX(-90deg) translateZ(100px); }
The translateZ value should equal half the cube's side length — 100px for a 200×200×200 cube.
Common Pitfalls
- Missing
transform-style: preserve-3d— without it, child elements are flattened into the parent's 2D plane and Z-axis transforms disappear. overflow: hiddenbreaks 3D — settingoverflow: hiddenon a 3D-transformed element flattens its children. Useclip-pathinstead if you need to clip.backface-visibilityon the wrong element — it belongs on each face, not the container.
Key Takeaways
- 3D transforms add a Z axis for positioning, rotating, and scaling in depth.
perspectiveon a parent creates the illusion of depth; lower values are more dramatic.transform-style: preserve-3dkeeps children in 3D space — without it, everything flattens.- Card flips combine
rotateYwithbackface-visibility: hiddenon each face. - Carousels and cubes distribute faces evenly using
rotateY/NandtranslateZ. overflow: hiddendestroys 3D rendering — useclip-pathfor clipping instead.
Try It Yourself
Build 3D transform effects visually with the CSS Transform Tool.