CSS Scroll-Driven Animations: 5 Pure-CSS Scroll Animation Patterns Without JavaScript

前端工程

CSS Scroll-Driven Animations: Silky Smooth Scrolling Without JS

Parallax with JS scroll listeners causing jank, verbose IntersectionObserver code, requestAnimationFrame performance overhead — scroll animations have long depended on JavaScript. CSS Scroll-Driven Animations let you implement parallax, progress bars, and reveal animations purely in CSS: zero JS, 60fps, automatic GPU acceleration. In 2026, CSS scroll-driven animations are fully supported in Chrome and Safari.

This article covers 5 core patterns, guiding you through scroll-timeline → view-timeline → parallax → progress indicator → reveal animations.


Core Concepts

Concept Description
scroll-timeline Animation timeline based on scroll position
view-timeline Animation timeline based on element visibility
animation-timeline Specifies which scroll timeline an animation uses
animation-range Start and end positions of animation within scroll range
scroll() Anonymous scroll timeline function
view() Anonymous view timeline function
scroll-progress Scroll progress 0-1
view-progress Visibility progress 0-1

Problem Analysis: 5 Major CSS Scroll Animation Challenges

  1. Browser compatibility: Firefox support lags behind
  2. Difficult debugging: DevTools scroll animation support is limited
  3. Nested scrolling: Non-document scroll container configuration is complex
  4. Animation range calculation: animation-range percentage has high understanding cost
  5. Fallback: Unsupported browsers need JS fallback

Step-by-Step: 5 CSS Scroll Animation Patterns

Pattern 1: scroll-timeline Scroll Progress Animation

/* Page top progress bar */
@keyframes progress-bar {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

.progress-bar {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 3px;
  background: linear-gradient(90deg, #6366f1, #ec4899);
  transform-origin: left;
  animation: progress-bar linear;
  animation-timeline: scroll(root);
}

Pattern 2: view-timeline Viewport Reveal Animation

@keyframes reveal-up {
  from {
    opacity: 0;
    transform: translateY(60px) scale(0.95);
    filter: blur(4px);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
    filter: blur(0);
  }
}

.card {
  animation: reveal-up linear both;
  animation-timeline: view();
  animation-range: entry 0% entry 80%;
}

Pattern 3: Parallax Scrolling Effect

@keyframes parallax-slow {
  from { transform: translateY(0); }
  to { transform: translateY(-100px); }
}

@keyframes parallax-fast {
  from { transform: translateY(0); }
  to { transform: translateY(-300px); }
}

.parallax-bg {
  animation: parallax-slow linear both;
  animation-timeline: scroll(root);
}

.parallax-fg {
  animation: parallax-fast linear both;
  animation-timeline: scroll(root);
}

Pattern 4: Named Scroll Timeline

.scroller {
  overflow-y: auto;
  scroll-timeline-name: --my-scroller;
  scroll-timeline-axis: block;
}

@keyframes rotate-icon {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

.rotating-icon {
  animation: rotate-icon linear;
  animation-timeline: --my-scroller;
}

Pattern 5: Complex Animation Sequences

@keyframes hero-sequence {
  0% {
    opacity: 0;
    transform: translateY(100px) scale(0.8);
    filter: blur(10px);
  }
  30% {
    opacity: 1;
    transform: translateY(0) scale(1);
    filter: blur(0);
  }
  70% {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
  100% {
    opacity: 0;
    transform: translateY(-50px) scale(0.95);
  }
}

.hero-title {
  animation: hero-sequence linear both;
  animation-timeline: view();
  animation-range: entry 0% exit 100%;
}

Pitfall Guide

Pitfall 1: Not specifying animation-timeline

/* ❌ Wrong: missing animation-timeline */
.element {
  animation: slide-in 1s linear;
  /* Animation won't follow scroll */
}

/* ✅ Correct: specify scroll timeline */
.element {
  animation: slide-in linear both;
  animation-timeline: view();
}

Pitfall 2: Wrong animation-range values

/* ❌ Wrong: range exceeds scroll range */
.element {
  animation-range: entry 0% entry 200%; /* 200% invalid */
}

/* ✅ Correct: use valid range */
.element {
  animation-range: entry 0% entry 100%;
}

Pitfall 3: Transform conflicting with scroll

/* ✅ Correct: use will-change hint */
.parallax {
  animation: parallax linear both;
  animation-timeline: scroll(root);
  will-change: transform;
}

Pitfall 4: Not handling fallback

/* ✅ Correct: provide fallback */
@supports (animation-timeline: view()) {
  .card {
    animation: reveal-up linear both;
    animation-timeline: view();
  }
}

@supports not (animation-timeline: view()) {
  .card { opacity: 1; transform: none; }
}

Pitfall 5: Scroll container without overflow

/* ✅ Correct: ensure container is scrollable */
.scroller {
  overflow-y: auto;
  scroll-timeline-name: --my-scroll;
}

Error Troubleshooting

# Error Cause Solution
1 Animation doesn't follow scroll No animation-timeline set Add animation-timeline: view() or scroll()
2 Animation ends early animation-range too small Increase range
3 Wrong parallax direction scroll-timeline-axis misconfigured Use block/inline for direction
4 Named timeline invalid scroll-timeline-name mismatch Ensure parent-child names match
5 Animation jank No will-change Add will-change: transform
6 Firefox not working Browser doesn't support Use @supports for fallback
7 Nested scroll not working Inner/outer scroll conflict Use named scroll-timeline
8 Animation jumping Keyframes not smooth enough Add more keyframes or use linear
9 Fixed elements abnormal transform affects fixed positioning Move fixed elements outside transform container
10 Mobile not smooth GPU acceleration not enabled Add transform: translateZ(0)

Advanced Optimization

  1. Scroll Snap + Scroll Animations: Combining paged scrolling with animations
  2. CSS Houdini custom properties: Register animation properties for complex effects
  3. prefers-reduced-motion: Respect user preference for reduced motion
  4. Container queries + scroll animations: Responsive and scroll animation synergy
  5. WAAPI + Scroll Timeline: Web Animations API combined with CSS scroll timelines

Comparison

Dimension CSS Scroll-Driven JS IntersectionObserver JS scroll event GSAP ScrollTrigger
Performance ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐⭐
Code Volume ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐ ⭐⭐⭐⭐
Browser Support ⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
Flexibility ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
Debugging Ease ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐
Learning Curve ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐

Summary: CSS scroll-driven animations let you achieve silky smooth scrolling effects with zero JS, far outperforming JS solutions. CSS scroll animations suit scroll interaction scenarios pursuing extreme performance, especially parallax, progress bars, and reveal animations. With full Chrome and Safari support in 2026, use with @supports fallback.


Online Tools

Try these browser-local tools — no sign-up required →

#CSS滚动动画#Scroll-Driven#视差效果#CSS动画#2026#前端工程