with one click
web-animation-css-animations
CSS Animation patterns - transitions, keyframes, scroll-driven animations, @property, GPU-accelerated properties, accessibility with prefers-reduced-motion
Menu
CSS Animation patterns - transitions, keyframes, scroll-driven animations, @property, GPU-accelerated properties, accessibility with prefers-reduced-motion
| name | web-animation-css-animations |
| description | CSS Animation patterns - transitions, keyframes, scroll-driven animations, @property, GPU-accelerated properties, accessibility with prefers-reduced-motion |
Quick Guide: Use CSS transitions for state changes (hover, focus),
@keyframesfor autonomous/looping animations, scroll-driven animations for scroll-linked effects. Animate onlytransformandopacityfor 60fps. Always respectprefers-reduced-motion.
<critical_requirements>
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST animate ONLY transform and opacity for GPU-accelerated 60fps performance)
(You MUST respect prefers-reduced-motion using @media (prefers-reduced-motion: no-preference) for opt-in or @media (prefers-reduced-motion: reduce) for opt-out)
(You MUST use CSS custom properties for ALL timing values - NO magic numbers like 0.3s)
(You MUST use ease-out for enter animations and ease-in for exit animations - NEVER linear for UI transitions)
(You MUST remove will-change after animation completes - permanent will-change wastes GPU memory)
</critical_requirements>
Auto-detection: CSS animation, CSS transition, @keyframes, transform, opacity, transition-duration, animation-duration, prefers-reduced-motion, scroll-timeline, animation-timeline, will-change, cubic-bezier, ease-out, ease-in, @property
When to use:
When NOT to use:
Detailed Resources:
CSS animations leverage the browser's compositor thread for smooth, 60fps animations that don't block JavaScript execution. By animating only GPU-accelerated properties (transform and opacity), animations run on a separate thread from the main JavaScript thread.
Core principles:
transform and opacity to avoid layout/paint triggersprefers-reduced-motion user preferences@keyframes for animations that loop, auto-play, or have multiple stepsDefine timing, easing, and distance tokens as CSS custom properties for consistency. See examples/core.md for the full token setup.
:root {
--duration-instant: 100ms;
--duration-fast: 150ms;
--duration-normal: 250ms;
--duration-slow: 400ms;
--ease-out: cubic-bezier(0, 0, 0.2, 1); /* Enter */
--ease-in: cubic-bezier(0.4, 0, 1, 1); /* Exit */
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); /* Symmetric */
--ease-spring: cubic-bezier(0.175, 0.885, 0.32, 1.275); /* Bouncy */
--lift-sm: -2px;
--lift-md: -4px;
}
Why tokens matter: Consistent timing across application, easy to adjust globally, semantic naming communicates intent
Only animate transform and opacity. Never animate layout properties like width, height, top, left, margin, or padding.
/* CORRECT - GPU-accelerated */
.card {
transition:
transform var(--duration-fast) var(--ease-out),
opacity var(--duration-fast) var(--ease-out);
}
.card:hover {
transform: translateY(var(--lift-md)) scale(1.02);
}
/* WRONG - triggers layout recalculation every frame */
.card {
transition: all 0.3s linear;
}
.card:hover {
top: -8px;
margin-top: -8px;
}
Transform mapping: Use translate() instead of top/left, scale() instead of width/height, pseudo-element opacity instead of box-shadow.
See examples/core.md for button states, card hover effects, and the pseudo-element shadow technique.
Every animation must respect user motion preferences. Two strategies:
/* Base: no motion */
.element {
opacity: 1;
transform: translateY(0);
}
/* Opt-in to motion */
@media (prefers-reduced-motion: no-preference) {
.element {
animation: fade-slide-in var(--duration-normal) var(--ease-out);
}
}
.notification {
animation: slide-in-bounce var(--notification-duration) var(--ease-spring);
}
@media (prefers-reduced-motion: reduce) {
.notification {
animation: fade-in calc(var(--notification-duration) * 0.5) var(--ease-out);
}
}
Key insight: Reduced motion does not mean no animation. Opacity fades are generally safe. Replace spatial movement with opacity-only alternatives.
See examples/core.md for the complete reduced motion pattern.
Use @keyframes for animations that loop, auto-play on mount, or have more than two states.
@keyframes fade-slide-in {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.modal {
--modal-enter-duration: 300ms;
animation: fade-slide-in var(--modal-enter-duration) var(--ease-out) forwards;
}
Key details:
forwards fill mode to retain final state after animationbackwards fill mode to show initial state during animation-delayease-out for enter, ease-in for exitlinear is only appropriate for continuous rotation (spinners)See examples/core.md for spinners, pulses, skeleton loaders, and toast animations. See examples/keyframes.md for scroll-driven animations, @property gradients, and complex sequences.
will-change creates a GPU layer (~307KB per 320x240px element). Apply only when needed, remove after.
/* CORRECT - only during interaction */
.card:hover {
will-change: transform;
}
/* WRONG - permanent GPU layer on every element */
* {
will-change: transform;
}
Never apply will-change permanently. Each element with will-change creates a separate compositing layer that consumes GPU memory. On mobile devices, this can crash the browser.
CSS animation-timeline allows scroll-linked animations without JavaScript.
.progress-bar {
animation: grow-width linear;
animation-timeline: scroll();
}
@keyframes grow-width {
from {
transform: scaleX(0);
}
to {
transform: scaleX(1);
}
}
Two timeline types:
scroll() -- progress based on scroll container positionview() -- progress based on element visibility in viewportBrowser support: Chrome/Edge 115+, Safari 26+, Firefox behind flag
See examples/keyframes.md for scroll progress, viewport reveal, and parallax patterns.
CSS Houdini's @property enables animating custom properties like gradient angles that CSS cannot normally interpolate.
@property --gradient-angle {
syntax: "<angle>";
initial-value: 0deg;
inherits: false;
}
.gradient-border {
background: linear-gradient(var(--gradient-angle), #ff0080, #7928ca);
animation: rotate-gradient 3s linear infinite;
}
@keyframes rotate-gradient {
to {
--gradient-angle: 360deg;
}
}
Browser support: Chrome/Edge 85+, Safari 16.4+, Firefox 128+
For 60fps, each frame must complete in 16.67ms. Layout-triggering animations often exceed this budget.
| Category | Properties | Impact |
|---|---|---|
| Composite only (Best) | transform, opacity | No layout, no paint, GPU-accelerated |
| Paint only (Okay) | color, background-color, visibility | No layout, but repaints |
| Layout + Paint (Avoid) | width, height, margin, padding, top, left | Full page recalculation |
| Animation Type | Duration | Reason |
|---|---|---|
| Micro-interactions | 100-150ms | Feels instant |
| UI transitions | 200-300ms | Sweet spot for perception |
| Page transitions | 300-500ms | Major context change |
| Complex sequences | 500-1000ms | Story-telling moments |
| Instead of... | Use... |
|---|---|
top, left | translate(x, y) |
width, height | scale() |
box-shadow | Pseudo-element with opacity |
margin, padding | translate() with layout space |
<decision_framework>
Is the animation triggered by user interaction (hover, focus, class toggle)?
├─ YES → Is it a simple A->B state change?
│ ├─ YES -> CSS Transition
│ └─ NO -> Does it need multiple steps?
│ ├─ YES -> CSS @keyframes
│ └─ NO -> CSS Transition is fine
└─ NO -> Does it auto-play or loop?
├─ YES -> CSS @keyframes
└─ NO -> CSS Transition (triggered by class toggle)
What type of motion?
├─ Element entering -> ease-out (fast start, slow end)
├─ Element exiting -> ease-in (slow start, fast end)
├─ Symmetric motion -> ease-in-out
├─ Continuous rotation -> linear
├─ Playful/bouncy -> custom cubic-bezier with overshoot
└─ Default UI -> ease-out
Never use:
├─ linear for UI transitions (feels robotic)
└─ ease (browser default) for production (too generic)
Does the animation need...
├─ Pause/play/reverse/seek control? -> JavaScript (Web Animations API)
├─ Dynamic values calculated at runtime? -> JavaScript or CSS custom properties
├─ Physics-based springs? -> Your animation library
├─ Orchestrated staggering across many elements? -> JavaScript for complex, CSS for simple
├─ Scroll-linked progress? -> CSS scroll-driven animations
├─ Page/view transitions? -> See the View Transitions skill
└─ Simple state transitions? -> CSS Transitions
</decision_framework>
<red_flags>
width, height, top, left, margin, padding) -- triggers expensive reflows every frame; use transform instead0.3s, 300ms inline) -- all durations must be CSS custom propertiesprefers-reduced-motion -- every animation must respect user preferenceslinear feels robotic; use ease-out for enter, ease-in for exitwill-change -- creates GPU layers permanently, wasting memory; apply only during animationtransition: all -- transitions unnecessary properties, causes surprises when new properties are addedbox-shadow directly -- causes repaint every frame; use pseudo-element with opacityforwards on enter animations -- element snaps back to initial statetransform + position: fixed -- transform creates new containing block, breaking fixed positioning relative to viewportwill-change creates stacking context -- can affect z-index behavior unexpectedlydisplay: none -- use opacity + visibility or grid-template-rows: 0frfill-mode: backwards needed for delayed animations -- without it, element shows in final state during delaystroke-dashoffset and stroke-dasharray, not transform for path drawingoverflow: hidden parent breaks scroll-timeline</red_flags>
<critical_reminders>
All code must follow project conventions in CLAUDE.md
(You MUST animate ONLY transform and opacity for GPU-accelerated 60fps performance)
(You MUST respect prefers-reduced-motion using @media (prefers-reduced-motion: no-preference) for opt-in or @media (prefers-reduced-motion: reduce) for opt-out)
(You MUST use CSS custom properties for ALL timing values - NO magic numbers like 0.3s)
(You MUST use ease-out for enter animations and ease-in for exit animations - NEVER linear for UI transitions)
(You MUST remove will-change after animation completes - permanent will-change wastes GPU memory)
Failure to follow these rules will cause jank, accessibility issues, and degraded user experience.
</critical_reminders>
Generate AI videos with Luma Dream Machine via AceDataCloud API. Use when creating videos from text prompts, generating videos from reference images, extending existing videos, or any video generation task with Luma. Supports text-to-video, image-to-video, and video extension.
Single-pass post-processing, URP Renderer Features, and mobile-safe screen effects for Unity
GPU architecture, precision types, fillrate, overdraw, baked lighting, and LOD optimization for Unity mobile/WebGL shaders
Node budgets, custom lighting, sub-graphs, precision control, and mobile workflows for Unity Shader Graph
Channel packing, variant reduction, shader_feature vs multi_compile, and build size optimization for Unity
Mobile-optimized water shaders with depth coloring, foam, Gerstner waves, refraction, and caustics for Unity URP