Intermediate11 min read

3D Transforms in CSS: perspective, rotateX, rotateY, and translateZ

11 min read
377 words
21 sections16 code blocks

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:

CSS
.container {
  perspective: 1000px;
}

.card {
  transform: rotateY(45deg);
}

Lower vs Higher Perspective Values

CSS
/* 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()

CSS
/* 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):

CSS
.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:

CSS
.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:

CSS
.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:

CSS
.spin {
  transform: rotateZ(45deg);
  /* Identical to: transform: rotate(45deg); */
}

rotate3d() — Combined Rotation

CSS
/* rotate3d(x, y, z, angle) */
.complex-rotation {
  transform: rotate3d(1, 1, 0, 45deg);
}

3D Translation

translateZ() — Moving in Depth

CSS
.closer {
  transform: translateZ(100px);  /* Moves toward viewer */
}

.farther {
  transform: translateZ(-100px); /* Moves away from viewer */
}

translateZ requires perspective to be visible.

translate3d() — Combined Translation

CSS
/* 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:

CSS
.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:

CSS
.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

CSS
.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

CSS
.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

CSS
.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

CSS
.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.