Note: Only animatable properties can transition (transform,
opacity, colors, etc.). Avoid transition: all in production (performance). Use specific properties
instead.
Note: Use animation-fill-mode: forwards to keep final state. infinite
loops should be performance-optimized. Use @keyframes for complex, multi-step
animations.
Note: Use ease-out for entrances, ease-in for exits, ease-in-out for movement. Tools
like cubic-bezier.com help create custom curves. Material Design: cubic-bezier(0.4, 0.0, 0.2, 1).
4. Scroll-triggered Animations Experimental
Feature
Syntax
Description
Browser Support
animation-timeline
scroll() | view()
Link animation to scroll position
Chrome 115+
scroll()
scroll(axis container)
Scroll container timeline
Limited
view()
view(axis inset)
Element in viewport timeline
Limited
animation-range
start-point end-point
When animation plays during scroll
Chrome 115+
animation-range-start
cover 0% | contain 25%
When animation starts
Chrome 115+
animation-range-end
cover 100% | contain 75%
When animation ends
Chrome 115+
Example: Scroll-driven animations (modern CSS)
/* Fade in as element enters viewport */@keyframes fadeInScroll { from { opacity: 0; transform: translateY(50px); } to { opacity: 1; transform: translateY(0); }}.scroll-reveal { animation: fadeInScroll linear; animation-timeline: view(); animation-range: entry 0% entry 100%;}/* Parallax effect with scroll */@keyframes parallax { to { transform: translateY(-100px); }}.parallax-bg { animation: parallax linear; animation-timeline: scroll();}/* Scale based on scroll position */@keyframes scaleOnScroll { from { transform: scale(0.8); } to { transform: scale(1); }}.scale-scroll { animation: scaleOnScroll linear; animation-timeline: view(); animation-range: entry 0% cover 50%;}/* Header shrink on scroll */@keyframes shrinkHeader { to { transform: scale(0.9); padding: 0.5rem 1rem; }}.header { animation: shrinkHeader linear; animation-timeline: scroll(root block); animation-range: 0 100px;}/* Rotate on scroll */@keyframes rotateScroll { to { transform: rotate(360deg); }}.rotate-element { animation: rotateScroll linear; animation-timeline: scroll();}/* Progress bar based on scroll */.progress-bar { position: fixed; top: 0; left: 0; height: 4px; background: blue; transform-origin: 0 50%; animation: scaleProgress linear; animation-timeline: scroll(root block);}@keyframes scaleProgress { from { transform: scaleX(0); } to { transform: scaleX(1); }}
Example: Scroll animations with Intersection Observer (fallback)
Warning:animation-timeline is experimental (Chrome
115+). Use Intersection Observer for production. Performance: limit scroll animations, use
will-change, prefer transform/opacity.
5. View Transition API Integration Experimental
API Method
Syntax
Description
Browser Support
document.startViewTransition()
startViewTransition(callback)
Create animated transition between states
Chrome 111+
view-transition-name
unique-name
Identify element for transition
Chrome 111+
::view-transition
Pseudo-element
Root transition container
Chrome 111+
::view-transition-group()
Pseudo-element
Group for specific transition
Chrome 111+
::view-transition-image-pair()
Pseudo-element
Old and new image container
Chrome 111+
::view-transition-old()
Pseudo-element
Outgoing state snapshot
Chrome 111+
::view-transition-new()
Pseudo-element
Incoming state snapshot
Chrome 111+
Example: View Transition API basics
/* Mark elements for view transitions */.card { view-transition-name: card-1;}.title { view-transition-name: title;}/* Customize transition animation */::view-transition-old(card-1),::view-transition-new(card-1) { animation-duration: 0.5s;}/* Custom animation for specific transition */@keyframes slide-from-right { from { transform: translateX(100%); }}::view-transition-new(card-1) { animation: slide-from-right 0.5s ease-out;}/* Fade transition */::view-transition-old(root) { animation: 0.3s ease-out both fade-out;}::view-transition-new(root) { animation: 0.3s ease-out both fade-in;}@keyframes fade-out { to { opacity: 0; }}@keyframes fade-in { from { opacity: 0; }}/* JavaScript usage *//*// Simple transitionfunction updateView() { document.startViewTransition(() => { // Update DOM here document.querySelector('.content').textContent = 'New content'; });}// With promise handlingasync function animatedUpdate() { const transition = document.startViewTransition(() => { // DOM updates updateDOMState(); }); await transition.finished; console.log('Transition complete');}// Conditional transitionsfunction conditionalTransition() { if (document.startViewTransition) { document.startViewTransition(() => updateDOM()); } else { updateDOM(); // Fallback without animation }}*/
Example: Advanced View Transition patterns
/* Different transitions for different elements */.hero { view-transition-name: hero;}.sidebar { view-transition-name: sidebar;}/* Hero expands */::view-transition-new(hero) { animation: scaleUp 0.5s ease-out;}@keyframes scaleUp { from { transform: scale(0.8); }}/* Sidebar slides in */::view-transition-new(sidebar) { animation: slideInLeft 0.4s ease-out;}@keyframes slideInLeft { from { transform: translateX(-100%); }}/* Morph between layouts */.grid-item { view-transition-name: attr(data-id); /* Dynamic names */}/* Smooth color transitions */::view-transition-group(root) { animation-duration: 0.5s; animation-timing-function: ease-in-out;}/* Page transition (SPA navigation) */::view-transition-old(root) { animation: fadeOutScale 0.3s ease-in;}::view-transition-new(root) { animation: fadeInScale 0.3s ease-out;}@keyframes fadeOutScale { to { opacity: 0; transform: scale(0.95); }}@keyframes fadeInScale { from { opacity: 0; transform: scale(1.05); }}/* Disable transition for specific elements */.no-transition { view-transition-name: none;}/* Cross-fade between images */.image-container { view-transition-name: main-image;}::view-transition-old(main-image),::view-transition-new(main-image) { animation-duration: 0.4s; height: 100%; object-fit: cover;}/* Custom easing for smooth transitions */::view-transition-group(*) { animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1);}
Warning: View Transitions API is experimental (Chrome 111+). Not
yet in Firefox/Safari. Always provide fallback. Only works for same-document transitions. Feature detection
required: if (document.startViewTransition) { }