Skip to main content
March 23, 2026Dan Rodney/11 min read

GreenSock: Intro to Scrolling Animations (ScrollTrigger)

Master scroll-based animations with GSAP ScrollTrigger plugin

Core ScrollTrigger Concepts

ScrollTrigger Setup

Learn to configure scroll-based animations that trigger when elements enter the viewport. Essential for modern interactive web experiences.

Toggle Actions

Control animation behavior at four key scroll positions: onEnter, onLeave, onEnterBack, and onLeaveBack for complete scroll control.

Scrubbing Effects

Link animations directly to scrollbar position for smooth, interactive scroll experiences that respond to user input in real-time.

Topics Covered in This JavaScript Tutorial:

Setting up a ScrollTrigger, Toggle Actions, Turning on Markers, Scrubbing: Linking an Animation to the Scrollbar, Starting & Ending Scroll Positions

Exercise Preview

preview scrolltrigger

Exercise Overview

ScrollTrigger represents one of the most powerful features in the GSAP ecosystem, transforming static animations into dynamic, scroll-driven experiences that engage users naturally. In this comprehensive exercise, you'll master the fundamentals of GSAP's ScrollTrigger plugin, learning to create animations that respond intelligently to user scroll behavior. This technique has become essential for modern web development, powering the sophisticated scroll interactions you see on leading websites across industries.

Exercise Goal

You'll animate a heading 'What Makes Hipstirred Coffee Great?' when it scrolls into view, transforming from invisible and scaled down to full visibility and size.

Getting Started

  1. For this exercise we'll be working with the GSAP-ScrollTrigger-Intro folder located in Desktop > Class Files > JavaScript Class. Open that folder in your code editor if it allows you to (like Visual Studio Code does).
  2. In your code editor, open index.html from the GSAP-ScrollTrigger-Intro folder.
  3. Preview index.html in Chrome. (We'll be using its DevTools for debugging and performance monitoring throughout this exercise.)

    • Scroll down and below the photo notice there's a heading What Makes Hipstirred Coffee Great?
    • We want to animate this heading when it first scrolls into view, creating a more engaging user experience than traditional page-load animations.

Project Setup Steps

1

Open Project Folder

Navigate to Desktop > Class Files > JavaScript Class and open the GSAP-ScrollTrigger-Intro folder in your code editor

2

Launch Files

Open index.html in your code editor and preview it in Chrome browser for testing

3

Locate Target Element

Scroll down to find the heading 'What Makes Hipstirred Coffee Great?' below the photo - this is what we'll animate

Linking to the GSAP Scripts

Before we can harness ScrollTrigger's capabilities, we need to properly load both the core GSAP library and the ScrollTrigger plugin. Modern web development best practices recommend loading JavaScript files at the bottom of your HTML document for optimal performance.

  1. First we need to link to the GSAP JavaScript file. Add the following bold code before the closing </body> tag:

    <script src="js/gsap.min.js"></script>
    </body>
  2. ScrollTrigger is not part of the GSAP core library, so we must load it separately as a plugin. This modular approach keeps the core library lightweight while allowing developers to add only the features they need:

    <script src="js/gsap.min.js"></script>
       <script src="js/ScrollTrigger.min.js"></script>
    </body>
  3. Add an empty script tag below that for our custom code:

    <script src="js/gsap.min.js"></script>
       <script src="js/ScrollTrigger.min.js"></script>
       <script></script>
    </body>
  4. Create a basic animation for the heading (which targets the only h2 tag on the page):

    <script>
       gsap.from('h2', {duration:5, opacity:0, scale:0.5});
    </script>
  5. Save your changes and switch back to Chrome to test the animation.

    • Scroll up to the top and reload the page.
    • Wait a moment and then scroll down to see the What Makes Hipstirred Coffee Great? heading just below the top photo.
    • Notice the headline is either finishing or has already finished its animation. This timing issue demonstrates why scroll-based triggers are superior to page-load animations—they ensure users actually see the animated content.
Script Loading Order

ScrollTrigger is not part of GSAP core and must be loaded separately after the main GSAP library. Always load gsap.min.js first, then ScrollTrigger.min.js.

Script Implementation

1

Add GSAP Core

Include the main GSAP library script before the closing body tag

2

Add ScrollTrigger Plugin

Load ScrollTrigger.min.js after the core GSAP script

3

Create Custom Script Tag

Add an empty script tag below the libraries for your custom animation code

4

Test Basic Animation

Add a simple gsap.from animation targeting the h2 element with opacity and scale properties

Setting up a ScrollTrigger

Now we'll transform our basic animation into a scroll-triggered experience that activates precisely when the user needs to see it.

  1. Add the scrollTrigger property to link the animation to scroll position:

    gsap.from('h2', {scrollTrigger:'h2',  duration:5, opacity:0, scale:0.5});
  2. Save and switch back to your browser to observe the improved behavior.

    • Scroll up to the top and reload the page.
    • Pause a moment and then scroll down deliberately.

    When the trigger element (the heading) enters the viewport, it automatically triggers the animation to start. This creates a much more intentional and engaging user experience compared to timeline-based animations that begin when the page loads, regardless of user attention.

  3. Test the scrolling behavior by moving up and down so the heading scrolls off both the top and bottom of the screen multiple times.

    Notice the animation only triggers once and doesn't repeat when the element re-enters the viewport. This default behavior prevents animation overload, but we'll soon learn how to customize this response.

Timeline vs ScrollTrigger Animation Timing

FeatureTimeline AnimationScrollTrigger Animation
Start TriggerPage loadElement enters viewport
User ControlNoneScroll-based
PerformanceAlways runningContext-aware
Recommended: ScrollTrigger provides better user experience and performance for scroll-based interactions

Toggle Actions

Toggle actions give you precise control over animation behavior at four critical scroll positions, enabling sophisticated interactions that respond to user movement patterns.

  1. To access advanced scrollTrigger options, we need to convert it from a simple string to a configuration object. Change the scrollTrigger from 'h2' to {} as shown below:

    gsap.from('h2', {scrollTrigger:{}, duration:5, opacity:0, scale:0.5});
  2. Improve code readability by adding strategic line breaks:

    gsap.from('h2', {
       scrollTrigger:{}, duration:5, opacity:0, scale:0.5
    });
  3. Further organize the structure by adding line breaks inside the scrollTrigger object:

    gsap.from('h2', {
       scrollTrigger:{
    
       }, 
       duration:5, opacity:0, scale:0.5
    });
  4. Configure the trigger element and introduce toggle actions for enhanced control:

    scrollTrigger:{
       trigger:'h2', 
       toggleActions:'restart none none none'
    }, 

    Toggle Action Positions

    onEnter
    25
    onLeave
    25
    onEnterBack
    25
    onLeaveBack
    25

    Toggle Action Controls

    onEnter

    Controls animation when element enters viewport from bottom. Default action is 'play' to start the animation sequence.

    onLeave

    Controls animation when element leaves viewport at top. Set to 'pause' to stop animation when not visible for better performance.

    onEnterBack & onLeaveBack

    Handle reverse scroll scenarios. Use 'resume' and 'pause' to create smooth bidirectional scroll experiences.

Understanding ToggleActions

From the official GSAP documentation at greensock.com/docs/v3/Plugins/ScrollTrigger

toggleActions controls animation behavior at four distinct scroll positions—onEnter, onLeave, onEnterBack, and onLeaveBack, in that exact order. The default setting is 'play none none none'.

For example, toggleActions: 'play pause resume reset' will play the animation when the element enters the viewport, pause it when leaving, resume it when entering again from the top, and reset (rewind to the beginning) when scrolling back past the starting position. This granular control enables sophisticated user experiences that respond intelligently to scroll behavior.

  • Save and reload the page in Chrome to test the new toggle behavior.

    ToggleActions provide granular control over animation states as elements move in and out of the viewport from different directions. Our current setting uses restart for the onEnter action, which means the animation will begin fresh each time the element comes into view from below.

    • Scroll down and observe how the animation starts when the heading enters the window from below.
    • Continue scrolling so the heading moves off the top of the window, then bring it back into view—notice it doesn't animate again because we haven't defined an onEnterBack action.
    • Scroll up so the heading disappears off the bottom of the window.
    • Scroll back down to see the animation restart every time the heading enters from the bottom, exactly as our configuration specifies.
  • Configure the second toggle action to pause animations that move off-screen:

    scrollTrigger:{
       trigger:'h2', 
       toggleActions:'restart pause none none'
    }
  • Save and reload the page in Chrome to test the pause functionality.

    We've now set onLeave (when the element scrolls off the top of the window) to pause, which improves performance by stopping animations that users cannot see.

    • Scroll down to start the heading animation, but continue scrolling quickly so the heading moves off the top of the screen before the animation completes.
    • When the heading leaves the top of the viewport, the animation will pause mid-execution.
    • Bring the heading back into view and notice the animation remains paused—we need to configure the resume action next.
  • Set the third toggle action to resume paused animations:

    scrollTrigger:{
       trigger:'h2', 
       toggleActions:'restart pause resume none'
    }
  • Save and reload the page in Chrome to test the resume functionality.

    We've configured onEnterBack (when the element scrolls into view from the top of the window) to resume, creating seamless animation continuity.

    • Scroll down to start the heading animation, then continue scrolling so it moves off the top before completing.
    • When the heading leaves the top of the screen, the animation pauses as before.
    • Bring the heading back down into view and observe how the animation smoothly resumes from where it left off, rather than starting over.
  • Ctrl–click (Mac) or Right–click (Windows) on the animated heading and choose Inspect to open Chrome DevTools.
  • Monitor the animation in DevTools as you trigger it by bringing the heading into view from the bottom.

    During animation, you'll see colored highlighting and dynamic changes in the DevTools Elements panel—this visual feedback confirms when GSAP is actively animating properties. Once the animation completes, the highlighting disappears.

    Test performance optimization by triggering the animation again, then quickly scrolling the heading off the bottom of the screen. Notice in DevTools that the animation continues running even when the element is invisible. This unnecessary processing wastes system resources and can impact scroll performance on lower-end devices.

  • Complete the toggle actions by setting the final action to pause:

    scrollTrigger:{
       trigger:'h2', 
       toggleActions:'restart pause resume pause'
    }
  • Save and reload the page in Chrome to test the complete toggle action configuration.

    We've now set onLeaveBack (when the element scrolls off the bottom of the window) to pause, ensuring optimal performance by stopping animations whenever they move out of view.

    • Scroll down to start the heading animation, but quickly scroll back up so the heading moves off the bottom of the screen while still animating.
    • Check the DevTools Elements panel—the colored highlighting should stop immediately, confirming GSAP has paused the animation. This performance optimization prevents wasted processing power on invisible animations.
  • Turning on Markers

    GSAP's visual markers provide invaluable debugging information, showing exactly when and where scroll triggers activate. This visualization tool is essential for understanding and fine-tuning scroll-based animations.

    1. Enable visual debugging markers (note the comma on the preceding line):

      scrollTrigger:{
         trigger:'h2', 
         toggleActions:'restart pause resume pause', 
         markers:true
      }, 
    2. Save and reload the page in Chrome to see the debugging visualization:

      • You'll see scroller-start at the bottom right of the viewport and scroller-end at the top right.
      • As you scroll, the animation triggers precisely when the start marker meets the scroller-start line.
      • The scroller-end marker will become relevant when we implement scrubbing functionality in the next section.
    Development vs Production

    Markers are invaluable for understanding scroll trigger positions during development. Always remove markers:true before deploying to production for clean user experience.

    Scrubbing: Linking an Animation to the Scrollbar

    Scrubbing creates one of the most engaging scroll interactions by directly linking animation progress to scroll position. This technique enables users to control animation playback through natural scroll behavior, creating intuitive and responsive experiences.

    1. Enable scrubbing to link animation progress directly to scroll position:

      scrollTrigger:{
         trigger:'h2', 
         toggleActions:'restart pause resume pause', 
         markers:true, 
         scrub:true
      }, 
    2. Remove conflicting properties that don't apply to scrubbed animations:

      gsap.from('h2', {
         scrollTrigger:{
            trigger:'h2', 
            markers:true, 
            scrub:true
         }, 
         opacity:0, scale:0.5
      });

      Note that we've removed toggleActions and duration because scrubbed animations are controlled entirely by scroll position rather than time-based playback or toggle behaviors.

    3. Save and reload the page in Chrome to experience scrub-controlled animation.

      • Notice how the animation now responds directly to your scroll input—dragging down or up plays the animation forward or backward in perfect synchronization with scroll position.
      • The animation begins at the bottom of the window and continues until the element reaches the top, creating a very long animation zone. We'll refine this behavior in the next section by customizing start and end positions.

    Scrubbing vs Toggle Actions

    Pros
    Animation directly tied to scroll position
    Smooth bidirectional control
    Immediate visual feedback
    No duration property needed
    Cons
    Can feel jerky without smoothing
    May impact scroll performance
    Less predictable timing
    Requires careful start/end positioning
    Performance Optimization

    Set scrub to a time value like 2 seconds instead of true to smooth out jerky animations and create more polished scroll experiences.

    Starting & Ending Scroll Positions

    Precise control over when animations begin and end is crucial for creating polished scroll experiences. Custom start and end positions ensure animations play within the optimal viewing zone.

    1. Define custom start and end positions for more precise animation control:

      scrollTrigger:{
         trigger:'h2', 
         markers:true, 
         scrub:true, 
         start:'top 80%', 
         end:'bottom 20%'
      }, 
      • The syntax follows the pattern: [element-position] [viewport-position]. The first value references the trigger element's edge, while the second value represents the distance from the top of the viewport.

      • In this configuration, the animation starts when the top of the heading reaches 80% down from the top of the window, and ends when the bottom of the heading reaches 20% down from the top of the window.

      You can use keywords (top, center, bottom), pixel values, or percentages for both positions. Percentages are always calculated relative to the top of the viewport, making them ideal for responsive designs that work across different screen sizes.

    2. Save and reload the page in Chrome to observe the refined animation zone:

      • The scroller-start marker now appears 80% down from the top of the window, while scroller-end sits at 20% from the top.

      • Animation begins precisely when the start marker aligns with scroller-start and completes when end aligns with scroller-end.

      • While scrubbing provides direct control, rapid scrolling can sometimes cause jerky or harsh animation playback. We'll smooth this behavior by adding temporal smoothing.

    3. Add temporal smoothing to create more polished scrub animations:

      scrollTrigger:{
         trigger:'h2', 
         markers:true, 
         scrub:2, 
         start:'top 80%', 
         end:'bottom 20%'
      }, 
    4. Save and reload the page in Chrome to experience the smoothed animation.

      By setting scrub to 2 seconds, the animation will take up to 2 seconds to catch up with rapid scroll changes, creating much smoother visual transitions. This technique eliminates the jarring effects of instant animation changes while maintaining the responsive feel of scroll-driven animation.

    5. Remove the debugging markers for the final production version:

      scrollTrigger:{
         trigger:'h2', 
         scrub:2, 
         start:'top 80%', 
         end:'bottom 20%'
      }, 
    6. Save and reload the page in Chrome to enjoy your completed scroll animation.

      The final result demonstrates professional-grade scroll animation: smooth, performant, and precisely timed to enhance the user experience without overwhelming the content.

    Professional Tip: This example demonstrates adding ScrollTrigger to a single tween, but the real power emerges when applying it to complex gsap.timeline() sequences—the same location where you've used the repeat property in previous exercises. Timelines with ScrollTrigger can orchestrate sophisticated multi-element animations that unfold as users explore your content.

    For comprehensive documentation and advanced techniques, explore the complete ScrollTrigger reference at greensock.com/docs/Plugins/ScrollTrigger. As scroll-driven animations continue to define modern web experiences in 2026, mastering these techniques positions you at the forefront of contemporary web development practices.

    Position Configuration

    1

    Define Start Position

    Set when animation begins using element position relative to viewport. 'top 80%' means element's top hits 80% down from viewport top

    2

    Define End Position

    Set when animation completes using 'bottom 20%' meaning element's bottom hits 20% down from viewport top

    3

    Use Flexible Units

    Combine keywords (top, center, bottom) with pixels or percentages for precise control across different screen sizes

    Final Implementation Checklist

    0/4

    Key Takeaways

    1ScrollTrigger requires separate loading after the main GSAP library and must be included as an additional script file
    2Toggle actions control animation behavior at four distinct scroll positions: onEnter, onLeave, onEnterBack, and onLeaveBack
    3Setting toggleActions to pause animations when elements leave the viewport improves performance by stopping invisible animations
    4Scrubbing links animations directly to scrollbar position, creating interactive experiences that respond to scroll direction and speed
    5Markers are essential debugging tools during development but should be removed before production deployment
    6Start and end positions use element-relative and viewport-relative positioning to control exactly when animations begin and complete
    7Adding time values to scrub properties smooths out jerky animations and creates more polished scroll experiences
    8ScrollTrigger can be applied to both individual tweens and complex timelines for sophisticated scroll-based animation sequences

    RELATED ARTICLES