Page navigation feels jarring? The new CSS View Transitions API creates native app-like transitions without a single line of JavaScript.
The Basic Setup:
/* Enable view transitions for all navigations */
@view-transition {
navigation: auto;
}
/* Customize the transition */
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 0.3s;
animation-timing-function: ease-in-out;
}
/* Fade effect */
::view-transition-old(root) {
animation-name: fade-out;
}
::view-transition-new(root) {
animation-name: fade-in;
}
@keyframes fade-out {
to { opacity: 0; }
}
@keyframes fade-in {
from { opacity: 0; }
}
How It Works:
When the user navigates to a new page:
1. Browser captures a screenshot of the current page
2. Loads the new page in the background
3. Captures a screenshot of the new page
4. Animates between the two screenshots
All this happens automatically with just the CSS above. No JavaScript event listeners, no DOM manipulation, no library dependencies.
Advanced – Element-Specific Transitions:
/* Tag specific elements to transition smoothly */
.product-image {
view-transition-name: product-hero;
}
.price-badge {
view-transition-name: price-info;
}
/* Animate them differently */
::view-transition-old(product-hero),
::view-transition-new(product-hero) {
animation-duration: 0.5s;
height: 100%;
object-fit: cover;
}
::view-transition-old(price-info) {
animation: slide-out-right 0.3s ease-out;
}
::view-transition-new(price-info) {
animation: slide-in-left 0.3s ease-out;
}
@keyframes slide-out-right {
to { transform: translateX(100%); }
}
@keyframes slide-in-left {
from { transform: translateX(-100%); }
}
Real-World Example – E-Commerce Product Pages:
/* Product listing page */
.product-card img {
view-transition-name: var(--product-id);
/* Each product gets unique transition name */
}
/* Product detail page */
.hero-image {
view-transition-name: var(--product-id);
/* Same name = smooth morph from thumbnail to full size */
}
When users click a product thumbnail, it smoothly expands into the hero image on the detail page. No JavaScript libraries, no complex state management.
Why This Matters:
Before View Transitions API:
• React Router: +40KB bundle
• Framer Motion: +60KB bundle
• Custom JavaScript: 100+ lines of code
• Performance overhead from JS parsing and execution
With View Transitions API:
• 0KB JavaScript
• Native browser optimization
• Hardware-accelerated animations
• 20 lines of CSS
Browser Support (as of 2024):
✅ Chrome 111+
✅ Edge 111+
✅ Opera 97+
⚠️ Firefox: Behind flag
⚠️ Safari: In development
Graceful Degradation:
@supports (view-transition-name: none) {
/* View Transitions supported */
@view-transition { navigation: auto; }
}
@supports not (view-transition-name: none) {
/* Fallback for unsupported browsers */
* { transition: opacity 0.2s; }
}
In unsupported browsers, pages just load normally. No broken experience, no errors.
