perspective & perspective-origin for 3D
perspective creates a 3D viewing space for child elements, making 3D transforms visible. It's essential for 3D effects like card flips, rotations, and depth effects. perspective-origin controls the vanishing point where parallel lines appear to meet.
Understanding perspective
CSS
<!-- perspective: creates 3D viewing space -->
.container {
perspective: 1000px;
/* Creates 3D space for children -->
}
.child {
transform: rotateY(45deg);
/* 3D rotation now visible -->
}
<!-- Without perspective: no 3D effect -->
<!-- With perspective: child appears in 3D space -->
/* perspective value: distance to viewer -->
.close-perspective {
perspective: 500px;
/* Closer to viewer: more extreme 3D effect -->
}
.far-perspective {
perspective: 2000px;
/* Far from viewer: subtle 3D effect -->
}
/* Practical values -->
.default {
perspective: 1000px; /* balanced -->
}
.dramatic {
perspective: 600px; /* exaggerated 3D -->
}
.subtle {
perspective: 1500px; /* mild 3D -->
}Common perspective values
Value | Effect | Use Case |
|---|---|---|
500px | Extreme 3D distortion | Dramatic effects |
800px | Strong 3D effect | Noticeable depth |
1000px | Balanced 3D | Default, well-balanced |
1500px | Subtle 3D | Gentle depth |
2000px+ | Very subtle | Minimal 3D |
CSS
<!-- 3D card flip with perspective -->
<div class="scene">
<div class="card">
<div class="card-face front">Front</div>
<div class="card-face back">Back</div>
</div>
</div>
.scene {
perspective: 1000px;
width: 200px;
height: 200px;
}
.card {
position: relative;
width: 100%;
height: 100%;
transition: transform 0.6s;
transform-style: preserve-3d;
}
.card-face {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
}
.back {
transform: rotateY(180deg);
}
.scene:hover .card {
transform: rotateY(180deg);
}
<!-- Card flips in 3D space -->
/* 3D box effect -->
.scene {
perspective: 1000px;
}
.box {
width: 100px;
height: 100px;
position: relative;
transform-style: preserve-3d;
animation: rotate-box 4s infinite linear;
}
@keyframes rotate-box {
from { transform: rotateX(0) rotateY(0); }
to { transform: rotateX(360deg) rotateY(360deg); }
}
<!-- Box rotates in 3D -->
/* Tilting effect with perspective -->
.scene {
perspective: 800px;
}
.element {
transition: transform 0.3s;
}
.element:hover {
transform: rotateX(10deg) rotateY(10deg);
/* Tilts in 3D based on hover -->
}perspective-origin: viewing angle
CSS
<!-- perspective-origin: where you view from -->
.container {
perspective: 1000px;
perspective-origin: center;
/* Default: view from center -->
}
.element {
transform: rotateY(45deg);
}
<!-- View from center point -->
/* Different viewing angles -->
.from-top {
perspective: 1000px;
perspective-origin: center top;
/* View from above -->
}
.from-left {
perspective: 1000px;
perspective-origin: left center;
/* View from left side -->
}
.from-corner {
perspective: 1000px;
perspective-origin: top left;
/* View from top-left corner -->
}
/* Percentage values -->
.custom {
perspective: 1000px;
perspective-origin: 25% 75%;
/* View from custom point -->
}
<!-- Affects how 3D transforms appear -->
/* Practical: card flip from different angles -->
.card-container {
perspective: 1000px;
perspective-origin: right center;
/* View from right side -->
}
.card {
transition: transform 0.6s;
}
.card:hover {
transform: rotateY(180deg);
/* Flip appears from right perspective -->
}Advanced 3D with perspective
CSS
<!-- Multiple 3D transformations -->
.scene {
perspective: 1200px;
}
.element {
transition: transform 0.4s;
}
.element:hover {
transform: rotateX(20deg) rotateY(20deg) translateZ(50px);
/* Tilt and move toward viewer -->
}
<!-- Complex 3D motion -->
/* 3D gallery with perspective -->
.gallery {
perspective: 1000px;
display: flex;
gap: 20px;
}
.item {
width: 150px;
height: 150px;
transform-style: preserve-3d;
transition: transform 0.3s;
}
.item:hover {
transform: rotateY(15deg) rotateZ(-5deg);
/* Items tilt in 3D -->
}
<!-- Gallery items appear in 3D space -->
/* Depth layering -->
.scene {
perspective: 1000px;
}
.layer-1 { transform: translateZ(0px); }
.layer-2 { transform: translateZ(50px); }
.layer-3 { transform: translateZ(100px); }
<!-- Layers appear at different depths -->
/* transform-style: preserve-3d for nested 3D -->
.scene {
perspective: 1000px;
}
.container {
transform-style: preserve-3d;
transform: rotateX(10deg);
}
.child {
transform: translateZ(50px);
/* Child's translateZ is in parent's 3D space -->
}
<!-- Nested 3D transformations work correctly -->
/* Practical: dropdown menu with 3D perspective -->
.menu-trigger {
perspective: 1000px;
}
.menu {
transform-origin: top center;
transform-style: preserve-3d;
transition: transform 0.3s;
opacity: 0;
transform: rotateX(-90deg) translateZ(-10px);
}
.menu.open {
opacity: 1;
transform: rotateX(0deg) translateZ(0px);
}
<!-- Menu rotates down in 3D space -->Performance and best practices
CSS
<!-- Perspective on container, not individual elements -->
.good {
perspective: 1000px;
/* Apply once to container -->
}
.good > * {
transform: rotateY(45deg);
/* All children use same perspective -->
}
.bad {
perspective: 1000px;
}
.bad > * {
perspective: 1000px;
/* Don't repeat: inefficient -->
}
<!-- Apply perspective once to parent -->
/* Use backface-visibility for efficiency -->
.element {
backface-visibility: hidden;
/* Hide element when facing away from viewer -->
/* Improves performance for complex 3D -->
}
/* GPU-accelerated 3D rendering -->
.element {
perspective: 1000px;
/* Creates GPU layer for 3D -->
}
.child {
transform: translateZ(0);
/* Forces GPU acceleration -->
}
<!-- Modern browsers handle 3D well -->
/* Respect prefers-reduced-motion -->
@media (prefers-reduced-motion: reduce) {
* {
perspective: none;
transform: none;
}
}
<!-- Accessibility: disable 3D for motion-sensitive users -->
/* Testing perspective in DevTools -->
/* Open 3D view in DevTools (Chrome) -->
/* See perspective layers and depths -->
/* Helps debug 3D transforms -->Note
`perspective` creates a 3D viewing space; common values 800px-1500px. Lower values = more extreme 3D effect. Always apply perspective to parent, not individual elements. Use `transform-style: preserve-3d` for nested 3D, and `backface-visibility: hidden` to hide elements facing away. Modern browsers render 3D efficiently with GPU acceleration.
Next
3D transforms: [3D Transforms](/css/transforms-3d).