Scroll-Based Animations

    Lesson 30 โ€ข Advanced Track

    What You'll Learn

    Create scroll-driven progress bars with pure CSS animation-timeline
    Reveal elements on scroll using IntersectionObserver
    Use CSS view() timelines for element-entry animations
    Build parallax effects without JavaScript
    Understand when to use each scroll animation technique

    ๐Ÿ’ก Think of It Like This

    Imagine a flipbook โ€” as you flip pages (scroll), the animation progresses. Scroll-driven animations tie CSS animations to your scroll position instead of a clock. The faster you scroll, the faster the animation plays. IntersectionObserver works differently โ€” it's like a motion sensor on a door that triggers once when someone walks through.

    Understanding Scroll Animations

    There are three main approaches to animating content based on scroll position. The best choice depends on browser support requirements, the type of effect you want, and performance considerations.

    CSS Scroll-Driven Animations (the newest approach) let you bind any CSS animation directly to the scroll position using animation-timeline: scroll(). The animation progress maps 1:1 with how far the user has scrolled. This is ideal for progress bars, parallax backgrounds, and scroll-linked colour changes โ€” but browser support is still limited to Chromium browsers.

    IntersectionObserver is the established cross-browser solution for "reveal on scroll" effects. It fires a callback when an element enters or exits the viewport, letting you toggle CSS classes. It's the industry standard for lazy loading images, fade-in animations, and infinite scroll pagination.

    Approach Comparison

    MethodBrowser SupportThreadBest For
    animation-timeline: scroll()Chrome 115+CompositorProgress bars, parallax, scroll-linked effects
    animation-timeline: view()Chrome 115+CompositorElement-entry animations, scroll reveals
    IntersectionObserverAll modernMain (async)Reveal-on-scroll, lazy load, infinite scroll
    scroll event + rAFUniversalMainFine-grained control (last resort)

    1. Scroll-Driven Progress Bar (CSS)

    Try it Yourself ยป
    Code Preview
    <!DOCTYPE html>
    <html>
    <head>
        <style>
            body { font-family: system-ui, sans-serif; margin: 0; }
            .progress-bar {
                position: fixed; top: 0; left: 0; height: 4px;
                background: linear-gradient(90deg, #F44336, #FF9800, #4CAF50, #2196F3);
                width: 0%;
                z-index: 1000;
                animation: grow-progress auto linear;
                animation-timeline: scroll();
            }
            @keyframes grow-progress { to { width: 100%; } }
            .hero {
      
    ...

    How scroll() works: The animation-timeline: scroll() property replaces the default time-based timeline. At 0% scroll, the animation is at its from state. At 100% scroll, it reaches to. The animation-duration is ignored (set to auto) because progress is controlled by scroll position, not time.

    2. Reveal on Scroll (IntersectionObserver)

    Try it Yourself ยป
    Code Preview
    <!DOCTYPE html>
    <html>
    <head>
        <style>
            body { font-family: system-ui, sans-serif; padding: 0; margin: 0; }
            .spacer { height: 50vh; display: flex; align-items: center; justify-content: center;
                background: #f5f5f5; color: #999; font-size: 1.2rem; }
            .reveal {
                opacity: 0; transform: translateY(40px);
                transition: opacity 0.6s ease, transform 0.6s ease;
                max-width: 600px; margin: 40px auto; padding: 24px;
                background:
    ...

    Step-by-Step: IntersectionObserver

    Step 1: Set elements to opacity: 0 and transform: translateY(40px) by default.

    Step 2: Add a .visible class that resets opacity and transform with a transition.

    Step 3: Create an observer with a threshold (0.15 = trigger when 15% visible).

    Step 4: When the observer fires, add the .visible class. The CSS transition handles the animation smoothly.

    3. View Timeline Element Animations (CSS)

    Try it Yourself ยป
    Code Preview
    <!DOCTYPE html>
    <html>
    <head>
        <style>
            body { font-family: system-ui, sans-serif; margin: 0; padding: 0; }
            .spacer { height: 80vh; display: flex; align-items: center; justify-content: center; background: #f0f0f0; color: #999; font-size: 1.2rem; }
            .animate-card {
                max-width: 500px; margin: 60px auto; padding: 32px;
                background: white; border-radius: 16px;
                box-shadow: 0 4px 20px rgba(0,0,0,0.1);
                animation: slide-in auto ease-
    ...

    view() vs scroll(): scroll() ties to the overall page scroll (0-100%). view() ties to when a specific element enters and exits the viewport. Use animation-range: entry 0% entry 100% to control exactly when the animation starts and completes relative to the element's visibility.

    4. CSS Parallax Effect

    Try it Yourself ยป
    Code Preview
    <!DOCTYPE html>
    <html>
    <head>
        <style>
            body { font-family: system-ui, sans-serif; margin: 0; overflow-x: hidden; }
            .parallax-section {
                position: relative; height: 70vh; overflow: hidden;
                display: flex; align-items: center; justify-content: center;
            }
            .parallax-bg {
                position: absolute; inset: -20%; z-index: -1;
                background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
                animation: paralla
    ...

    ๐Ÿ’ก When to Use This

    • Progress indicators: Reading progress bars, step indicators, loading animations tied to scroll
    • Content reveals: Fade-in sections, staggered card animations on landing pages
    • Parallax: Background layers moving at different speeds for depth
    • Lazy loading: IntersectionObserver to load images only when they enter the viewport
    • Infinite scroll: Trigger data fetching when a sentinel element becomes visible

    โš ๏ธ Common Mistakes

    • Using scroll event listeners for simple reveals โ€” IntersectionObserver is more performant and simpler. Scroll listeners fire on every pixel of scroll movement.
    • Forgetting browser support for animation-timeline โ€” As of 2024, only Chromium supports it. Always provide an IntersectionObserver fallback for Safari/Firefox users.
    • Animating too many elements simultaneously โ€” Revealing 20+ elements at once causes frame drops. Stagger entries using transition-delay or threshold differences.
    • Not using unobserve() after reveal โ€” If you only want a one-time reveal, call observer.unobserve(entry.target) after adding the visible class to free resources.
    • Missing @media (prefers-reduced-motion) โ€” Some users have motion sensitivity. Disable or simplify scroll animations when reduced motion is preferred.
    • Using will-change on every animated element โ€” Only use it on elements that actually need GPU promotion. Each promoted layer consumes GPU memory.

    ๐ŸŽ‰ Lesson Complete

    • โœ… animation-timeline: scroll() binds animation to scroll position
    • โœ… animation-timeline: view() triggers when an element enters/exits viewport
    • โœ… animation-range controls exactly when the animation starts and ends
    • โœ… IntersectionObserver is the cross-browser standard for scroll reveals
    • โœ… Use threshold to control when elements trigger (0 to 1)
    • โœ… Prefer transform/opacity for jank-free scroll animations
    • โœ… Parallax effects work by translating background layers at different scroll rates
    • โœ… Always respect prefers-reduced-motion for accessibility

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy Policy โ€ข Terms of Service