Skip to main content

CSS 2D and 3D Transforms

The transform property allows you to visually reposition, resize, rotate, and skew elements without affecting page layout. Transformed elements don't push other elements around — they move in their own visual layer, making transforms extremely smooth to animate.

1. Transform Functions Overview

/* All transform functions can be combined in one rule */
.element {
transform: translateX(20px) rotate(15deg) scale(1.1);
}

2. Translate (Move)

Moves the element without affecting other elements' positions.

/* Single axis */
.up { transform: translateX(50px); } /* Right 50px */
.down { transform: translateY(-20px); } /* Up 20px */

/* Both axes */
.shifted { transform: translate(30px, -10px); }

/* Percentage of its OWN size — very useful! */
.centered {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%); /* Classic absolute centering trick */
}

3. Rotate

.clockwise { transform: rotate(45deg); } /* Clockwise 45° */
.counter { transform: rotate(-90deg); } /* Counter-clockwise 90° */
.half-spin { transform: rotate(180deg); } /* Upside down */

/* Individual axes (3D) */
.card-flip { transform: rotateY(180deg); } /* Flip horizontal */
.lean { transform: rotateX(15deg); } /* Tilt toward viewer */

4. Scale

.larger { transform: scale(1.2); } /* 20% larger */
.smaller { transform: scale(0.8); } /* 20% smaller */
.x-stretch { transform: scaleX(2); } /* 2× width only */
.y-stretch { transform: scaleY(0.5); } /* Half height */

/* Common hover effect */
.card:hover { transform: scale(1.03); }

5. Skew

.skewed-x { transform: skewX(20deg); }
.skewed-y { transform: skewY(-10deg); }
.skewed-btn { transform: skew(-15deg, 0); } /* Slanted button/banner */

6. transform-origin

By default, all transforms happen from the element's center. transform-origin changes that point:

/* Syntax: x-position y-position (or keyword) */
.fold-open { transform-origin: left center; transform: rotateY(-90deg); } /* Fold from left */
.spin-corner { transform-origin: top left; transform: rotate(45deg); } /* Rotate from top-left */
.zoom-bottom { transform-origin: bottom center; transform: scale(0, 1); } /* Scale from bottom */

7. 3D Transforms

3D transforms require a perspective to be set on the parent container:

/* The parent sets perspective (distance from viewer to the 3D plane) */
.scene {
perspective: 800px; /* Smaller = more extreme effect */
}

/* Children use 3D transforms */
.card {
transform-style: preserve-3d; /* Children exist in 3D space */
transform: rotateY(20deg);
}

The Card Flip Component

.flip-card {
perspective: 1000px;
width: 300px;
height: 400px;
}
.flip-card__inner {
position: relative;
width: 100%;
height: 100%;
transform-style: preserve-3d;
transition: transform 0.7s cubic-bezier(0.4, 0.2, 0.2, 1);
}
.flip-card:hover .flip-card__inner { transform: rotateY(180deg); }

.flip-card__front,
.flip-card__back {
position: absolute;
inset: 0;
backface-visibility: hidden; /* Hides the back face when flipped away */
border-radius: 16px;
}
.flip-card__back { transform: rotateY(180deg); }

8. Combining Transforms

Order matters — transforms are applied right to left:

/* Different results! */
.a { transform: translateX(100px) rotate(45deg); } /* Translate THEN rotate */
.b { transform: rotate(45deg) translateX(100px); } /* Rotate THEN translate (moves diagonally) */

9. Matrix Transform

The matrix() and matrix3d() functions combine all transforms into a single mathematical expression. You won't write these by hand, but AI may generate them for complex animations:

/* These are equivalent: */
.a { transform: translateX(50px) rotate(30deg) scale(1.2); }
.b { transform: matrix(1.039, 0.6, -0.6, 1.039, 50, 0); }

10. Practical Patterns

Hover Lift Card

.card {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-8px);
box-shadow: 0 16px 40px rgba(0,0,0,0.3);
}

Rotating Arrow Icon (Accordion)

.accordion__icon {
transition: transform 0.3s ease;
}
.accordion[open] .accordion__icon {
transform: rotate(180deg);
}

Parallax on Scroll with Transform

.parallax-layer {
transform: translateY(calc(var(--scroll-y, 0) * 0.3)); /* Updated via JS */
}