Loading...

CSS 3D Transforms

Optional Advanced just tuned pointer, caret, and native chrome. This last optional session is a different toolkit: 3D transforms. You give a card a vanishing point and tilt it in depth. You are not remaking the 2D translate / scale hover lesson, and you are not choosing cursors or resize handles.

Direct answer

CSS 3D transforms use the same transform property as 2D, plus depth. Put perspective on a parent so children share a vanishing point (perspective-origin moves that point). rotateX and rotateY tilt around horizontal and vertical axes; rotateZ is the familiar flat spin. translateZ moves toward or away from the viewer. transform-style: preserve-3d keeps children in one 3D scene instead of flattening them. backface-visibility: hidden hides a face when it turns away — useful for a two-sided card. The layout slot still stays, as in 2D. Keep angles modest. Honor prefers-reduced-motion.

Why this is not 2D motion or UI chrome

The 2D transforms lesson taught plane motion: translate, rotate, scale, skew, and transform-origin for a hinge. Those still work. 3D adds a camera-like perspective and extra axes. User-interface CSS was interaction chrome (cursor, resize, caret-color, appearance). A rotated card does not need a lying hand cursor, and a textarea handle is not a vanishing point. If you only need a 2px lift, stay in 2D.

Perspective — put the camera on the parent

perspective is a length: smaller values feel closer and more dramatic; larger values feel flatter. Set it on the scene, not on every face, so siblings share one vanishing point.

Perspective on the parent

css
.stage {
perspective: 800px;
perspective-origin: 50% 40%;
}

.card-3d {
transform: rotateY(18deg);
transform-origin: center;
}

You can also write transform: perspective(800px) rotateY(18deg) on one element. That camera belongs only to that box. For a cube or a row of tiles, parent perspective is calmer. perspective-origin is the vanishing-point cousin of transform-origin — it does not replace origin on the rotating face.

Axes — rotateX, rotateY, rotateZ

Think of a book. rotateY swings the cover left–right. rotateX nods it toward you or away. rotateZ spins it on the page — the 2D rotate() you already know.

rotateX rotateY rotateZ

css
.tile-y {
transform: rotateY(-22deg);
}

.tile-x {
transform: rotateX(12deg);
}

.tile-z {
transform: rotateZ(8deg);
}

Chain with 2D functions when you need both: rotateY(16deg) translateZ(24px). Order matters — later functions run in the local space of earlier ones. Prefer one transform list, same habit as the 2D lesson. Huge rotateX(80deg) on a whole article is a carnival, not a UI.

translateZ — distance, not a layout shove

Positive translateZ often comes toward the viewer when perspective is set. Neighbors in the document do not make room; only the paint moves, like 2D translate.

translateZ in a 3D scene

css
.stage {
perspective: 900px;
}

.pop-face {
transform: translateZ(40px) rotateY(-8deg);
}

.back-face {
transform: translateZ(-28px);
}

Use translateZ to separate faces of a scene, not to fake margin or z-index for ordinary stacking. z-index still orders overlapping boxes in 2D layout; 3D distance is a different knob. If the job is “lift a chip 2px,” translateY from the 2D lesson is enough.

preserve-3d — keep a scene, do not flatten

By default, a parent flattens transformed children (transform-style: flat). Nested faces then lose their 3D relationship. For a cube, a stacked cover, or a card with two sides, set preserve-3d on the rotating wrapper.

preserve-3d on the scene

css
.scene {
perspective: 700px;
}

.rig {
transform-style: preserve-3d;
transition: transform 0.45s ease;
}

.rig.is-flipped {
transform: rotateY(180deg);
}

.face {
position: absolute;
inset: 0;
backface-visibility: hidden;
}

Every ancestor that should keep depth needs preserve-3d — one forgotten flat parent stamps the cube into a poster. perspective on the outer stage and preserve-3d on the inner rig is a common split: camera outside, joints inside.

backface-visibility — hide the reverse

When a face rotates past 90°, you would otherwise see it mirrored. backface-visibility: hidden drops that reverse. Pair two faces: front at rotateY(0), back at rotateY(180deg), both position: absolute on the same rig.

Card flip with backface-visibility

css
.card-rig {
position: relative;
transform-style: preserve-3d;
}

.card-front,
.card-back {
position: absolute;
inset: 0;
backface-visibility: hidden;
}

.card-back {
transform: rotateY(180deg);
}

Without hidden backs, you get a ghost of the front showing through. This is still not user-select: none and not appearance: none. You are hiding a painted face in 3D, not stripping a checkbox skin.

3D vs 2D transform vs UI chrome

📊 3D vs 2D transform vs UI chrome

Tool Job Poor fit
perspective + rotateX / rotateY / translateZ Depth scene: tilt, distance, shared vanishing point Everyday 2px hover lift; pointer shape
2D translate / rotate / scale / skew Motion in the plane; origin hinge Building a cube without preserve-3d
transform-style / backface-visibility Nested 3D faces; hide reversed sides Caret color; textarea resize
UI (cursor, resize, appearance…) Interaction chrome on controls Vanishing points; card flips

Optional Advanced already styled controls. Effects & Motion already taught 2D mapping. This session is the depth layer on transform. Mixing cursor: pointer onto a heading because it rotateYs does not make it 3D. Mixing perspective onto a login form does not replace resize on a notes field.

Calm habits

Keep perspective in the hundreds of pixels for UI cards (600px–1200px is a sane band). Do not set perspective: 40px on body. Prefer :hover / class toggles with a short transition on transform — same pairing as 2D. Gate flourish with prefers-reduced-motion: reduce (flatten to none or a tiny 2D nudge). Keyboard focus still needs a visible ring from earlier lessons; a flip is not a focus style.

Modest 3D hover not a 2D lift

css
.preview {
perspective: 1000px;
}

.preview .plate {
transition: transform 0.3s ease;
}

.preview:hover .plate {
transform: rotateY(-10deg) rotateX(4deg);
}

@media (prefers-reduced-motion: reduce) {
.preview .plate,
.preview:hover .plate {
transition: none;
transform: none;
}
}

That hover is a tilt, not the 2D translateY(-0.15rem) chip lift, and not resize: vertical on a field. If reduced-motion users would rather have a static card, believe them.

Try it yourself

  1. Wrap a card in .stage { perspective: 800px; } and set rotateY(20deg) on the child — then move perspective onto the child transform and compare sibling tiles.
  2. Build a two-face card: preserve-3d on the rig, backface-visibility: hidden on both faces, back face rotateY(180deg).
  3. Add translateZ(32px) on a front plane; confirm layout neighbors do not shift.
  4. Flip with a class + transition: transform — then flatten with prefers-reduced-motion.
  5. Do not solve this with cursor, resize, or a 2D-only translateY hover.

Common mistakes

  • perspective: 50px on body so the whole page warps
  • Forgetting preserve-3d on the wrapper, then wondering why a cube looks flat
  • Treating the 2D chip-lift (translateY) as a 3D lesson
  • Using UI chrome (cursor, resize, appearance) as a stand-in for depth
  • backface-visibility on the stage instead of the faces
  • Ignoring prefers-reduced-motion on large rotateY flips
  • Expecting 3D to change document flow the way margin does

Summary

  • 3D transforms add depth to transform: perspective, rotateX / rotateY, translateZ
  • Put perspective on the parent scene; use preserve-3d so nested faces stay in that space
  • backface-visibility: hidden hides a face that has turned away
  • Not a 2D hover-lift lesson and not user-interface chrome
  • Keep angles modest; respect reduced motion
  • This is the last CSS session in this course — Optional Advanced ends here; there is no further CSS slug in the map

🧠 Test Your Knowledge

Ready to Start

Test Your Knowledge

Challenge yourself with this interactive quiz and see how well you understand the topic

❓
7
Questions
🎯
70%
To Pass
♾️
∞
Time
🔄
∞
Attempts

📝 Instructions

  • Read each question carefully
  • Select the best answer for each question
  • You can retake the quiz as many times as you want
  • Your progress will be shown at the top