CSS Transforms and 3D Effects
1. CSS 2D Transform Functions (translate, rotate, scale, skew)
| Function | Syntax | Description | Example |
|---|---|---|---|
| translate() | translate(x, y) |
Move element in 2D space | translate(50px, 100px) |
| translateX() | translateX(x) |
Move horizontally | translateX(50px) |
| translateY() | translateY(y) |
Move vertically | translateY(100px) |
| scale() | scale(x, y) |
Scale element (1 = normal) | scale(1.5, 2) |
| scaleX() | scaleX(x) |
Scale horizontally | scaleX(2) |
| scaleY() | scaleY(y) |
Scale vertically | scaleY(0.5) |
| rotate() | rotate(angle) |
Rotate clockwise (deg, rad, turn) | rotate(45deg) |
| skew() | skew(x, y) |
Skew element along X and Y axes | skew(10deg, 5deg) |
| skewX() | skewX(angle) |
Skew horizontally | skewX(20deg) |
| skewY() | skewY(angle) |
Skew vertically | skewY(10deg) |
| matrix() | matrix(a, b, c, d, tx, ty) |
2D transformation matrix | matrix(1, 0, 0, 1, 0, 0) |
| Property | Values | Description | Default |
|---|---|---|---|
| transform | function() |
Apply transformation(s) | none |
| transform-origin | x y |
Transform origin point | 50% 50% |
| transform-box | content-box | border-box | fill-box | stroke-box | view-box |
Reference box for transform-origin | view-box |
Example: 2D transform basics
/* Translate (move) */
.move-right {
transform: translateX(100px);
}
.move-down {
transform: translateY(50px);
}
.move-diagonal {
transform: translate(100px, 50px);
}
/* Scale (resize) */
.scale-up {
transform: scale(1.5); /* 150% size */
}
.scale-down {
transform: scale(0.8); /* 80% size */
}
.scale-x {
transform: scaleX(2); /* Double width */
}
.flip-horizontal {
transform: scaleX(-1); /* Flip horizontally */
}
.flip-vertical {
transform: scaleY(-1); /* Flip vertically */
}
/* Rotate */
.rotate-45 {
transform: rotate(45deg);
}
.rotate-negative {
transform: rotate(-90deg); /* Counter-clockwise */
}
.rotate-full {
transform: rotate(1turn); /* 360 degrees */
}
/* Skew (shear) */
.skew-x {
transform: skewX(20deg);
}
.skew-both {
transform: skew(10deg, 5deg);
}
Example: Combining transforms
/* Multiple transforms (space-separated, applied right-to-left) */
.combined {
transform: translateX(100px) rotate(45deg) scale(1.2);
/* Order matters: scale, then rotate, then translate */
}
/* Hover effects */
.card {
transition: transform 0.3s ease;
}
.card:hover {
transform: translateY(-10px) scale(1.05);
/* Lift up and slightly enlarge */
}
/* Button press effect */
.button {
transform: scale(1);
transition: transform 0.1s;
}
.button:active {
transform: scale(0.95); /* Shrink slightly when pressed */
}
/* Parallax scroll effect */
.parallax-layer {
transform: translateY(calc(var(--scroll) * 0.5px));
}
/* Center with transform */
.centered {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
/* Rotate on hover */
.rotate-hover {
transition: transform 0.3s;
}
.rotate-hover:hover {
transform: rotate(360deg);
}
Note: Transforms don't affect document flow. Order matters:
transforms apply right-to-left. Use
translate() instead of positioning for better performance (GPU-accelerated).
2. CSS 3D Transform Properties (rotateX, rotateY, rotateZ)
| Function | Syntax | Description | Example |
|---|---|---|---|
| translateZ() | translateZ(z) |
Move along Z-axis (toward/away viewer) | translateZ(100px) |
| translate3d() | translate3d(x, y, z) |
Move in 3D space | translate3d(50px, 100px, 200px) |
| scaleZ() | scaleZ(z) |
Scale along Z-axis | scaleZ(2) |
| scale3d() | scale3d(x, y, z) |
Scale in 3D space | scale3d(1, 1, 2) |
| rotateX() | rotateX(angle) |
Rotate around X-axis (horizontal) | rotateX(45deg) |
| rotateY() | rotateY(angle) |
Rotate around Y-axis (vertical) | rotateY(180deg) |
| rotateZ() | rotateZ(angle) |
Rotate around Z-axis (same as rotate()) | rotateZ(90deg) |
| rotate3d() | rotate3d(x, y, z, angle) |
Rotate around custom axis | rotate3d(1, 1, 0, 45deg) |
| matrix3d() | matrix3d(16 values) |
3D transformation matrix | Complex transformations |
| Property | Values | Description | Default |
|---|---|---|---|
| transform-style | flat | preserve-3d |
How child elements render in 3D | flat |
| backface-visibility | visible | hidden |
Show/hide back face when rotated | visible |
| perspective | none | length |
3D perspective distance (parent) | none |
| perspective-origin | x y |
Vanishing point position | 50% 50% |
Example: 3D transforms
/* Basic 3D rotation */
.rotate-x {
transform: rotateX(45deg);
}
.rotate-y {
transform: rotateY(180deg); /* Flip horizontally in 3D */
}
.rotate-z {
transform: rotateZ(90deg); /* Same as rotate(90deg) */
}
/* 3D translation */
.move-forward {
transform: translateZ(100px); /* Toward viewer */
}
.move-backward {
transform: translateZ(-100px); /* Away from viewer */
}
/* 3D card flip */
.card {
transform-style: preserve-3d;
transition: transform 0.6s;
}
.card.flipped {
transform: rotateY(180deg);
}
.card-front,
.card-back {
backface-visibility: hidden;
position: absolute;
}
.card-back {
transform: rotateY(180deg);
}
/* 3D cube */
.cube {
transform-style: preserve-3d;
transform: rotateX(-20deg) rotateY(30deg);
}
.cube-face {
position: absolute;
width: 200px;
height: 200px;
backface-visibility: hidden;
}
.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); }
Example: 3D effects and interactions
/* Perspective container (required for 3D) */
.scene {
perspective: 1000px; /* Viewing distance */
}
/* 3D hover tilt effect */
.tilt-card {
transform-style: preserve-3d;
transition: transform 0.3s;
}
.tilt-card:hover {
transform: rotateX(10deg) rotateY(10deg) scale(1.05);
}
/* 3D carousel */
.carousel-3d {
transform-style: preserve-3d;
}
.carousel-item {
position: absolute;
transform-style: preserve-3d;
}
.carousel-item:nth-child(1) { transform: rotateY(0deg) translateZ(300px); }
.carousel-item:nth-child(2) { transform: rotateY(72deg) translateZ(300px); }
.carousel-item:nth-child(3) { transform: rotateY(144deg) translateZ(300px); }
.carousel-item:nth-child(4) { transform: rotateY(216deg) translateZ(300px); }
.carousel-item:nth-child(5) { transform: rotateY(288deg) translateZ(300px); }
/* 3D book open effect */
.book {
transform-style: preserve-3d;
}
.book-cover {
transform-origin: left;
transition: transform 0.8s;
}
.book.open .book-cover {
transform: rotateY(-180deg);
}
/* 3D parallax layers */
.parallax-3d {
perspective: 1000px;
}
.layer {
transform-style: preserve-3d;
}
.layer-1 { transform: translateZ(0px); }
.layer-2 { transform: translateZ(-50px); }
.layer-3 { transform: translateZ(-100px); }
Note: Parent needs
perspective for 3D effect. Child needs
transform-style: preserve-3d. Use backface-visibility: hidden for flip cards.
3. Transform Origin and Perspective (transform-origin, perspective)
| Property | Values | Description | Example |
|---|---|---|---|
| transform-origin | x y z |
Point around which transforms occur | top left, 50% 50% |
| X position | left | center | right | length | % |
Horizontal origin | left, 100px, 25% |
| Y position | top | center | bottom | length | % |
Vertical origin | top, 50px, 75% |
| Z position | length |
Depth origin (3D) | 100px |
| Perspective Property | Values | Description | Effect |
|---|---|---|---|
| perspective | none | length |
Distance from viewer (on parent) | Smaller = more dramatic 3D |
| 500px | Close | Very dramatic 3D effect | Strong distortion |
| 1000px | Medium | Moderate 3D effect | Balanced |
| 2000px | Far | Subtle 3D effect | Gentle distortion |
| perspective-origin | x y |
Vanishing point (viewer position) | Changes viewing angle |
Example: Transform-origin variations
/* Default origin (center) */
.rotate-center {
transform-origin: center center; /* 50% 50% */
transform: rotate(45deg);
}
/* Corner origins */
.rotate-top-left {
transform-origin: top left; /* 0% 0% */
transform: rotate(45deg);
}
.rotate-bottom-right {
transform-origin: bottom right; /* 100% 100% */
transform: rotate(45deg);
}
/* Edge origins */
.rotate-left {
transform-origin: left center; /* Book spine effect */
transform: rotateY(90deg);
}
.rotate-top {
transform-origin: top center; /* Door opening down */
transform: rotateX(90deg);
}
/* Custom origin with length */
.rotate-custom {
transform-origin: 100px 50px;
transform: rotate(45deg);
}
/* 3D origin (with Z) */
.rotate-3d-origin {
transform-origin: center center -100px;
transform: rotateY(45deg);
}
/* Scale from corner */
.scale-corner {
transform-origin: top left;
transform: scale(2); /* Grows from top-left */
}
/* Swing animation */
@keyframes swing {
0%, 100% { transform: rotate(0deg); }
50% { transform: rotate(10deg); }
}
.swing {
transform-origin: top center; /* Pivot at top */
animation: swing 2s ease-in-out infinite;
}
Example: Perspective effects
/* Container perspective (affects all children) */
.scene {
perspective: 1000px;
perspective-origin: center center;
}
/* Strong perspective (close viewer) */
.dramatic-scene {
perspective: 500px;
}
/* Subtle perspective (distant viewer) */
.subtle-scene {
perspective: 2000px;
}
/* Off-center perspective */
.perspective-offset {
perspective: 1000px;
perspective-origin: 25% 75%; /* View from bottom-left */
}
/* Per-element perspective with transform */
.perspective-self {
/* Less common, applies to self not children */
transform: perspective(1000px) rotateY(45deg);
}
/* Perspective comparison */
.perspective-demo {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2rem;
}
.perspective-close {
perspective: 400px; /* Strong 3D */
}
.perspective-medium {
perspective: 1000px; /* Moderate 3D */
}
.perspective-far {
perspective: 2000px; /* Subtle 3D */
}
/* Mouse-tracking perspective */
.interactive-3d {
perspective: 1000px;
/* Update perspective-origin with JavaScript based on mouse position */
perspective-origin: var(--mouse-x, 50%) var(--mouse-y, 50%);
}
.interactive-3d .card {
transform: rotateX(calc(var(--mouse-y, 50) * 0.1deg))
rotateY(calc(var(--mouse-x, 50) * 0.1deg));
}
Note:
transform-origin sets the pivot point.
Default is center center. perspective must be on parent
container. Smaller perspective = stronger 3D effect.
4. CSS 3D Positioning and Camera
| Concept | Implementation | Description | Use Case |
|---|---|---|---|
| 3D Scene | perspective + preserve-3d |
Container with perspective and 3D rendering | 3D layouts, cards, galleries |
| Camera Position | perspective-origin |
Viewer's eye position (vanishing point) | View angle control |
| Camera Distance | perspective value |
Distance from viewer to scene | 3D strength control |
| Camera Rotation | Transform scene container | Rotate entire scene | Orbit, pan effects |
| Object Depth | translateZ() |
Position objects in 3D space | Layering, depth |
Example: 3D scene setup
/* Basic 3D scene structure */
.scene-3d {
perspective: 1200px;
perspective-origin: center center;
}
.stage {
transform-style: preserve-3d;
transform: rotateX(-10deg) rotateY(0deg);
transition: transform 0.5s;
}
.object-3d {
transform-style: preserve-3d;
position: absolute;
}
/* Position objects at different depths */
.object-near {
transform: translateZ(200px);
}
.object-middle {
transform: translateZ(0px);
}
.object-far {
transform: translateZ(-200px);
}
/* 3D card stack */
.card-stack {
perspective: 1000px;
}
.card-stack .card {
transform-style: preserve-3d;
}
.card-stack .card:nth-child(1) {
transform: translateZ(0px);
}
.card-stack .card:nth-child(2) {
transform: translateZ(-50px) translateY(10px);
}
.card-stack .card:nth-child(3) {
transform: translateZ(-100px) translateY(20px);
}
/* Rotate entire scene (camera orbit) */
.scene-3d:hover .stage {
transform: rotateX(-10deg) rotateY(20deg);
}
Example: Advanced 3D layouts
/* 3D Gallery with camera control */
.gallery-3d {
perspective: 1000px;
}
.gallery-stage {
transform-style: preserve-3d;
transform: translateZ(-500px);
}
.gallery-item {
position: absolute;
transform-style: preserve-3d;
backface-visibility: hidden;
}
/* Circular arrangement */
.gallery-item:nth-child(1) {
transform: rotateY(0deg) translateZ(500px);
}
.gallery-item:nth-child(2) {
transform: rotateY(60deg) translateZ(500px);
}
.gallery-item:nth-child(3) {
transform: rotateY(120deg) translateZ(500px);
}
/* And so on for 360° circle... */
/* 3D grid layout */
.grid-3d {
perspective: 1500px;
}
.grid-container {
transform-style: preserve-3d;
transform: rotateX(-20deg) rotateY(-20deg);
}
.grid-item {
transform: translateZ(calc(var(--row) * 50px + var(--col) * 20px));
}
/* Parallax layers with depth */
.parallax-scene {
perspective: 1000px;
overflow: hidden;
}
.parallax-layer {
transform-style: preserve-3d;
}
.parallax-layer-1 {
transform: translateZ(0px); /* Front */
}
.parallax-layer-2 {
transform: translateZ(-100px) scale(1.1); /* Scale compensates for size */
}
.parallax-layer-3 {
transform: translateZ(-200px) scale(1.2); /* Further back */
}
/* 3D isometric view */
.isometric {
perspective: 1000px;
}
.isometric-container {
transform-style: preserve-3d;
transform: rotateX(45deg) rotateZ(45deg);
}
.isometric-box {
transform-style: preserve-3d;
}
Example: Interactive 3D camera
/* Mouse-tracking 3D scene */
.interactive-scene {
perspective: 1000px;
/* Updated via JavaScript */
perspective-origin: var(--mouse-x, 50%) var(--mouse-y, 50%);
}
.interactive-stage {
transform-style: preserve-3d;
transform:
rotateX(calc(var(--rotate-x, 0) * 1deg))
rotateY(calc(var(--rotate-y, 0) * 1deg));
transition: transform 0.1s;
}
/* Scroll-based 3D rotation */
.scroll-3d {
perspective: 1200px;
}
.scroll-stage {
transform-style: preserve-3d;
transform: rotateY(calc(var(--scroll-progress, 0) * 360deg));
}
/* Device orientation 3D (mobile) */
.device-3d {
perspective: 1000px;
}
.device-stage {
transform-style: preserve-3d;
transform:
rotateX(calc(var(--beta, 0) * 1deg))
rotateY(calc(var(--gamma, 0) * 1deg));
}
/* Camera zoom effect */
@keyframes zoom-in {
from {
transform: translateZ(-1000px);
opacity: 0;
}
to {
transform: translateZ(0);
opacity: 1;
}
}
.zoom-element {
animation: zoom-in 1s ease-out;
}
/* Orbit camera animation */
@keyframes orbit {
from {
transform: rotateY(0deg);
}
to {
transform: rotateY(360deg);
}
}
.orbiting-stage {
transform-style: preserve-3d;
animation: orbit 20s linear infinite;
}
5. Hardware Acceleration (transform: translateZ) Optimization
| Technique | Implementation | Benefit | When to Use |
|---|---|---|---|
| GPU Acceleration | transform: translateZ(0) |
Promotes to GPU layer | Animated elements |
| will-change | will-change: transform |
Hint browser about changes | Before animations start |
| transform vs position | Use transform for movement |
Avoid layout recalculation | All animations |
| translate3d() | translate3d(x, y, 0) |
Forces 3D context (GPU) | 2D transforms needing GPU |
| Composite layers | Isolate animated elements | Reduce paint operations | Complex animations |
| Property | GPU Layer | Performance | Best For |
|---|---|---|---|
| transform | ✓ Yes | Fast (GPU) | Movement, rotation, scale |
| opacity | ✓ Yes | Fast (GPU) | Fade effects |
| filter | ✓ Yes | Moderate (GPU) | Visual effects |
| top/left/right/bottom | ✗ No | Slow (layout) | Avoid for animations |
| width/height | ✗ No | Slow (layout + paint) | Avoid for animations |
| background-color | ✗ No | Moderate (paint) | Use sparingly |
Example: Hardware acceleration techniques
/* Force GPU acceleration (translateZ hack) */
.gpu-accelerated {
transform: translateZ(0);
/* Creates new composite layer */
}
/* Or use translate3d */
.gpu-accelerated-alt {
transform: translate3d(0, 0, 0);
}
/* will-change for upcoming animations */
.about-to-animate {
will-change: transform;
/* Apply before animation, remove after */
}
.about-to-animate.animating {
transform: translateX(100px);
}
/* Remove will-change when done */
.animation-complete {
will-change: auto;
}
/* Optimize for smooth animations */
.smooth-animation {
/* Use GPU-accelerated properties only */
transition: transform 0.3s, opacity 0.3s;
}
/* Bad: triggers layout */
.bad-animation {
transition: left 0.3s, width 0.3s; /* Avoid! */
}
/* Good: GPU-accelerated */
.good-animation {
transition: transform 0.3s;
}
/* Isolate animated content */
.animated-card {
/* Create stacking context */
position: relative;
z-index: 0;
transform: translateZ(0);
}
Example: Performance best practices
/* Efficient movement */
/* Bad: reflows and repaints */
.move-bad {
animation: move-bad 1s;
}
@keyframes move-bad {
to { left: 100px; } /* Triggers layout */
}
/* Good: GPU-accelerated */
.move-good {
animation: move-good 1s;
}
@keyframes move-good {
to { transform: translateX(100px); } /* GPU */
}
/* Efficient fade */
/* Bad: might not be GPU-accelerated */
.fade-bad {
animation: fade-bad 1s;
}
@keyframes fade-bad {
to { visibility: hidden; }
}
/* Good: GPU-accelerated opacity */
.fade-good {
animation: fade-good 1s;
}
@keyframes fade-good {
to { opacity: 0; }
}
/* will-change management */
.element {
/* Don't apply will-change permanently */
}
.element:hover {
will-change: transform; /* Apply on hover */
}
.element.animating {
transform: scale(1.2);
}
/* JavaScript pattern for will-change */
/*
element.addEventListener('mouseenter', () => {
element.style.willChange = 'transform';
});
element.addEventListener('animationend', () => {
element.style.willChange = 'auto';
});
*/
/* Contain paint for isolated animations */
.isolated-animation {
contain: layout style paint;
/* Tells browser element doesn't affect outside */
}
/* Reduce composite layers (don't overuse) */
.many-elements .item {
/* Don't add translateZ(0) to every item */
/* Only on items that actually animate */
}
.many-elements .item.animated {
transform: translateZ(0); /* Only on animated items */
}
Warning: Overuse of
will-change can harm
performance. Apply temporarily before animations, remove after. Don't promote everything to GPU layers.
Only animate transform and opacity for best performance.
Transform & 3D Best Practices
- Use
transforminstead oftop/leftfor animations (GPU-accelerated) - Only animate transform and opacity for 60fps performance
- Set
perspectiveon parent,transform-style: preserve-3don children - Use
backface-visibility: hiddenfor flip cards - Set
transform-originfor custom pivot points (default: center) - Use
will-change: transformtemporarily before animations - Use
translate3d()ortranslateZ(0)to force GPU acceleration - Smaller
perspectivevalues = stronger 3D effect - Transform order matters: applied right-to-left