A card that flips to reveal a different back, a cube spinning on itself, a menu that seems to tilt toward the screen: these effects that create a genuine sense of depth, not just a flat resize or rotation, come from a 3D transform.
It extends transform by adding a third axis, the Z axis, running perpendicular to the screen, along with the notion of a perspective scene, without which no 3D transform produces any visible depth at all.
Definition
A 3D transform applies functions like rotateX(), rotateY(), rotateZ() or translateZ() to an element, on top of the usual 2D functions. Unlike an ordinary rotation or translation, these functions spin or move the element along an axis that runs out of the screen, which means the browser needs to know how to render that depth in perspective.
.card-3d {
transform: rotateY(180deg);
transition: transform 0.6s;
}perspective belongs on the parent, not the element
The most common pitfall in 3D transforms is setting the perspective property directly on the element that rotates, with no visible effect. perspective sets the imaginary distance between the viewer's eye and the screen: it needs to sit on the parent container, to create the 3D scene the child element will play out inside, never on the transformed element itself.
.card-container {
perspective: 1000px;
}
.card-3d {
transform: rotateY(180deg);
}perspective at all on the parent, a 3D rotation renders completely flat, with no depth whatsoever.translateZ() and the illusion of moving closer
translateZ() moves an element along the depth axis, toward the viewer with a positive value, or away with a negative one. Combined with perspective on the parent, this function creates the illusion that an element is genuinely moving closer to or farther from the screen, an effect impossible to achieve with scale() alone.
A concrete example: a card flipping on click
A memory-game card is a good example of perspective, rotateY() and backface-visibility working together. The parent sets up the 3D scene, the child rotates 180 degrees on click, and each of its two faces, front and back, sits absolutely positioned on top of the other with backface-visibility: hidden, so only the face currently turned toward the viewer stays visible at any point in the animation.
On browsers or devices that handle 3D effects poorly, it is worth planning a discreet fallback, such as a simple opacity change, rather than leaving a user staring at a frozen or distorted render.
The pivot point and stacking issues
As with any transformation, the rotation's pivot depends on transform-origin, often re-centered manually for a flipping card. A 3D-transformed element also creates its own stacking context, which can interfere with z-index on nearby elements that were not accounted for.
Frequently asked questions
It is almost always because the perspective property was never set anywhere, or was set directly on the transformed element instead of its parent container: without it, the browser applies the rotation in a depthless space, purely flat.
Yes, exactly like in 2D, by writing them one after another in the same transform declaration, for example transform: rotateY(30deg) translateZ(50px), with the writing order affecting the final result.
backface-visibility do anything specific in 3D?Yes, this related property decides whether the back face of an element flipped 180 degrees stays visible or gets hidden. On a card flipping to reveal a different back placed behind it, setting it to hidden prevents the front content from showing through, mirrored and transparent, on top of the back.