Loading...
Loading...
CSS-native animation techniques including Scroll-Driven Animations API, View Transitions, @property rule, and visual effects. Use when asked about: CSS animations, scroll-driven animations, CSS scroll timeline, view transitions, page transitions, @property, animating CSS variables, clip-path animations, backdrop-filter, mix-blend-mode, CSS masks, CSS-only animations, no-JavaScript animations, or when GSAP is not needed/wanted. Includes decision guide for CSS vs GSAP.
npx skill4agent add rshvr/elite-web-design elite-css-animations| Topic | Reference File |
|---|---|
| Scroll-Driven API | scroll-driven-api.md |
| View Transitions | view-transitions.md |
| @property Rule | property-rule.md |
| Visual Effects | visual-effects.md |
/* CSS: Hover states, simple transitions */
.card {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 10px 30px rgba(0,0,0,0.15);
}// GSAP: Complex scroll-driven sequences
gsap.timeline({
scrollTrigger: { trigger: '.section', scrub: 1 }
})
.from('.title', { opacity: 0, y: 50 })
.from('.content', { opacity: 0 }, '-=0.3');| Feature | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
| Scroll-Driven Animations | ✓ 115+ | ✓ 132+ | ✗ (polyfill) | ✓ 115+ |
| View Transitions | ✓ 111+ | ✗ | ✓ 18+ | ✓ 111+ |
| @property | ✓ 85+ | ✓ 128+ | ✓ 15.4+ | ✓ 85+ |
| clip-path animations | ✓ | ✓ | ✓ | ✓ |
| backdrop-filter | ✓ | ✓ | ✓ | ✓ |
/* Progress bar that fills as you scroll */
.progress-bar {
transform-origin: left;
transform: scaleX(0);
animation: progress linear;
animation-timeline: scroll();
}
@keyframes progress {
to { transform: scaleX(1); }
}/* Element reveals as it enters viewport */
@media (prefers-reduced-motion: no-preference) {
.reveal {
animation: fadeIn linear both;
animation-timeline: view();
animation-range: entry 0% cover 30%;
}
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(30px); }
to { opacity: 1; transform: translateY(0); }
}<script src="https://flackr.github.io/scroll-timeline/dist/scroll-timeline.js"></script>// Simple page transition
document.startViewTransition(() => {
// Update the DOM
updateContent();
});/* Customize the transition */
::view-transition-old(root) {
animation: fade-out 0.3s ease-out;
}
::view-transition-new(root) {
animation: fade-in 0.3s ease-in;
}
@keyframes fade-out {
to { opacity: 0; }
}
@keyframes fade-in {
from { opacity: 0; }
}@property --progress {
syntax: '<number>';
initial-value: 0;
inherits: false;
}
.progress-circle {
--progress: 0;
background: conic-gradient(
var(--color-accent) calc(var(--progress) * 360deg),
transparent 0
);
transition: --progress 1s ease-out;
}
.progress-circle.complete {
--progress: 1;
}.reveal {
clip-path: inset(0 100% 0 0);
transition: clip-path 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}
.reveal.visible {
clip-path: inset(0 0 0 0);
}.glass {
backdrop-filter: blur(10px) saturate(180%);
background: rgba(255, 255, 255, 0.7);
}.text-overlay {
mix-blend-mode: difference;
color: white;
}/* Default: No animation */
.animated {
opacity: 1;
transform: none;
}
/* Only animate if user allows */
@media (prefers-reduced-motion: no-preference) {
.animated {
animation: fadeIn 0.6s ease-out;
}
}/* GOOD - GPU accelerated */
.card {
transition: transform 0.3s, opacity 0.3s;
}
.card:hover {
transform: translateY(-4px) scale(1.02);
opacity: 0.9;
}
/* BAD - Triggers layout/paint */
.card:hover {
width: 110%;
margin-left: -5%;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
}/* Apply only during animation */
.animating {
will-change: transform, opacity;
}
/* Remove after animation */
.animation-complete {
will-change: auto;
}/* Isolate expensive effects */
.animated-section {
contain: layout style paint;
}.card {
transition:
transform 0.3s cubic-bezier(0.4, 0, 0.2, 1),
box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
}.item {
opacity: 0;
animation: fadeIn 0.5s ease forwards;
}
.item:nth-child(1) { animation-delay: 0.1s; }
.item:nth-child(2) { animation-delay: 0.2s; }
.item:nth-child(3) { animation-delay: 0.3s; }
/* ... or use CSS custom properties */
@keyframes fadeIn {
to { opacity: 1; }
}.spinner {
width: 40px;
height: 40px;
border: 3px solid var(--color-border);
border-top-color: var(--color-accent);
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}