Introduction to 3D transformations
CSS 3D transformations allow creating impressive visual effects without JavaScript. Thanks to the perspective, transform-style properties and 3D rotation functions, you can build immersive interfaces.
In this guide, we will explore 5 essential 3D effects: the rotating cube, the carousel, the card flip, depth effects and extruded 3D text. Each demo is interactive and the code is ready to copy.
perspective defines the observer's distance. transform-style: preserve-3d allows children to live in 3D space. backface-visibility hides the back face of elements.
1. Rotating 3D cube
The 3D cube is a classic for understanding CSS transformations. Each face is positioned in space using rotateY() and translateZ().
.cube-scene {
width: 150px;
height: 150px;
perspective: 600px;
}
.cube {
width: 100%;
height: 100%;
position: relative;
transform-style: preserve-3d;
animation: cubeRotate 8s infinite linear;
}
.cube-face {
position: absolute;
width: 150px;
height: 150px;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid rgba(99, 102, 241, 0.5);
background: rgba(99, 102, 241, 0.2);
}
/* Positioning the 6 faces */
.front { transform: rotateY(0deg) translateZ(75px); }
.back { transform: rotateY(180deg) translateZ(75px); }
.right { transform: rotateY(90deg) translateZ(75px); }
.left { transform: rotateY(-90deg) translateZ(75px); }
.top { transform: rotateX(90deg) translateZ(75px); }
.bottom { transform: rotateX(-90deg) translateZ(75px); }
@keyframes cubeRotate {
0% { transform: rotateX(0deg) rotateY(0deg); }
100% { transform: rotateX(360deg) rotateY(360deg); }
}
Key points
- translateZ(75px): Half the cube size (150px/2) to center each face
- transform-style: preserve-3d: Essential on the container for children to be in 3D
- perspective on the parent: Creates the depth of field
2. 3D Carousel
The 3D carousel arranges elements in a circle around a central axis. Each element is positioned at a different angle (360deg / number of elements).
.carousel-scene {
width: 100%;
height: 280px;
position: relative;
perspective: 1000px;
}
.carousel {
width: 200px;
height: 250px;
position: absolute;
left: 50%;
top: 50%;
transform-style: preserve-3d;
animation: carouselRotate 20s infinite linear;
}
.carousel-item {
position: absolute;
width: 200px;
height: 250px;
border-radius: 12px;
box-shadow: 0 25px 50px rgba(0,0,0,0.3);
}
/* 6 items = 360/6 = 60deg between each */
.carousel-item:nth-child(1) { transform: rotateY(0deg) translateZ(300px); }
.carousel-item:nth-child(2) { transform: rotateY(60deg) translateZ(300px); }
.carousel-item:nth-child(3) { transform: rotateY(120deg) translateZ(300px); }
.carousel-item:nth-child(4) { transform: rotateY(180deg) translateZ(300px); }
.carousel-item:nth-child(5) { transform: rotateY(240deg) translateZ(300px); }
.carousel-item:nth-child(6) { transform: rotateY(300deg) translateZ(300px); }
@keyframes carouselRotate {
from { transform: translate(-50%, -50%) rotateY(0deg); }
to { transform: translate(-50%, -50%) rotateY(-360deg); }
}
For N elements, the ideal translateZ distance is approximately: width / (2 * tan(180/N)). For 6 elements of 200px: 200 / (2 * tan(30)) = ~173px minimum.
3. 3D Card Flip
The card flip effect reveals a hidden face on hover or click. The backface-visibility: hidden property is essential to hide the back face of each side.
Front Face
Hover or click
Hidden content revealed! Perfect for info cards, products or memory games.
.flip-card {
width: 280px;
height: 180px;
perspective: 1000px;
cursor: pointer;
}
.flip-card-inner {
position: relative;
width: 100%;
height: 100%;
transition: transform 0.8s cubic-bezier(0.4, 0, 0.2, 1);
transform-style: preserve-3d;
}
.flip-card:hover .flip-card-inner {
transform: rotateY(180deg);
}
.flip-card-front,
.flip-card-back {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
}
.flip-card-front {
background: linear-gradient(135deg, #6366f1, #8b5cf6);
}
.flip-card-back {
background: linear-gradient(135deg, #8b5cf6, #d946ef);
transform: rotateY(180deg);
}
4. Depth effect (Layers)
By stacking layers with different translateZ values, we create a striking depth effect. On hover, the layers spread apart to reveal the structure.
.depth-scene {
width: 350px;
height: 250px;
position: relative;
transform-style: preserve-3d;
transform: rotateX(10deg) rotateY(-10deg);
transition: transform 0.3s ease;
}
.depth-layer {
position: absolute;
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
transition: transform 0.3s ease;
}
.layer-1 {
width: 100%; height: 100%;
background: rgba(99, 102, 241, 0.9);
transform: translateZ(0px);
}
.layer-2 {
width: 90%; height: 85%;
left: 5%; top: 7.5%;
background: rgba(139, 92, 246, 0.85);
transform: translateZ(40px);
}
.layer-3 {
width: 80%; height: 70%;
left: 10%; top: 15%;
background: rgba(217, 70, 239, 0.8);
transform: translateZ(80px);
}
.layer-4 {
width: 70%; height: 55%;
left: 15%; top: 22.5%;
background: linear-gradient(135deg, #f43f5e, #f59e0b);
transform: translateZ(120px);
}
/* Expansion on hover */
.depth-scene:hover {
transform: rotateX(0deg) rotateY(0deg);
}
.depth-scene:hover .layer-2 { transform: translateZ(60px); }
.depth-scene:hover .layer-3 { transform: translateZ(120px); }
.depth-scene:hover .layer-4 { transform: translateZ(180px); }
5. Extruded 3D text
3D text uses multiple stacked text-shadow to simulate extrusion. Combined with rotation, the effect is spectacular.
.text-3d-scene {
perspective: 500px;
}
.text-3d {
font-size: 4rem;
font-weight: 900;
color: #6366f1;
text-transform: uppercase;
letter-spacing: 0.1em;
transform: rotateX(15deg) rotateY(-15deg);
transform-style: preserve-3d;
animation: text3dFloat 4s ease-in-out infinite;
/* Extrusion via text-shadow empiles */
text-shadow:
1px 1px 0 #5558e3,
2px 2px 0 #4a4dd5,
3px 3px 0 #3f42c7,
4px 4px 0 #3437b9,
5px 5px 0 #292cab,
6px 6px 0 #1e219d,
7px 7px 0 #13168f,
8px 8px 0 #080b81,
9px 9px 15px rgba(0,0,0,0.4);
}
@keyframes text3dFloat {
0%, 100% {
transform: rotateX(15deg) rotateY(-15deg) translateY(0);
}
50% {
transform: rotateX(10deg) rotateY(-10deg) translateY(-10px);
}
}
Multiple text-shadows can impact performance on low-powered devices. Limit the number of layers and test on mobile.
Best practices
Here are the essential recommendations for performant and accessible 3D effects.
Performance
- Use
will-change: transformon animated elements to optimize GPU rendering - Limit the 3D elements simultaneously visible on the page
- Avoid complex shadows on continuously rotating elements
- Test on mobile: mobile GPUs are less powerful
Accessibility
/* Respect user preferences */
@media (prefers-reduced-motion: reduce) {
.cube,
.carousel,
.text-3d {
animation: none;
}
.flip-card-inner,
.depth-layer {
transition: none;
}
}
/* Alternative for touch interactions */
@media (hover: none) {
.flip-card:hover .flip-card-inner {
transform: none;
}
}
Browser compatibility
- Chrome, Edge, Firefox, Safari: Full support for several years
- iOS Safari: Watch out for bugs with
transform-stylein certain contexts - Prefixes: No longer necessary for modern 3D properties
Conclusion
CSS 3D transformations open a world of creative possibilities. By mastering perspective, transform-style and rotation functions, you can create memorable interfaces without JavaScript.
Experiment with values, combine techniques and don't forget: subtlety is often more effective than excess. A well-placed 3D effect draws attention; too many effects tire the user.
Find dozens of ready-to-use 3D effects in our effects library, with one-click copyable code.