GreenSock: Intro to Scrolling Animations (ScrollTrigger)

Free JavaScript Tutorial

Explore the intricacies of JavaScript animations linked to scroll positions as this tutorial guides you through the process of setting up a ScrollTrigger, toggle actions, and starting and ending scroll positions.

This exercise is excerpted from Noble Desktop’s JavaScript for Front-End training materials and is compatible with JavaScript updates through 2023. To learn current skills in JavaScript with hands-on training, check out our Front-End Web Development Certificate, Full-Stack Web Development Certificate, and coding classes in-person and live online.

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

In this exercise you’ll learn how to use GSAP’s ScrollTrigger plugin to start making animations that are based on scroll position within the page.

JavaScript Development Certificate: Live & Hands-on, In NYC or Online, 0% Financing, 1-on-1 Mentoring, Free Retake, Job Prep. Named a Top Bootcamp by Forbes, Fortune, & Time Out. Noble Desktop. Learn More.

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.)

    • Scroll down and below the photo notice there’s a heading What Makes Hipstirred Coffee Great?
    • We want to animate the heading when it first scrolls into view.

Linking to the GSAP Scripts

  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, so we have to load it separately:

       <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 code:

       <script src="js/gsap.min.js"></script>
       <script src="js/ScrollTrigger.min.js"></script>
       <script></script>
    </body>
    
  4. Add an animation for the heading (which is the only h2 tag):

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

    • Scroll up to the top and reload the page.
    • Wait a moment and then scroll down to see the What Makes Hipstirred Coffee Great? just below the top photo.
    • Notice the headline is either finishing or has finished its animation. That’s not good! Let’s make the animation happen when it scrolls into view.

Setting Up a ScrollTrigger

  1. Add the scrollTrigger property.

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

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

    When the trigger element (the heading) comes into view (enters the viewport), it triggers the animation to start. That’s very different from a timeline where the animations start from when the page loads.

  3. Scroll up and down so the heading scrolls scrolls off the top of the screen and scrolls off the bottom.

    Notice the animation only happened once and is not triggered again.

Toggle Actions

  1. To set additional scrollTrigger options, we need to change it into an object by changing the scrollTrigger from 'h2' to {} as shown below:

    gsap.from('h2', {scrollTrigger:{}, duration:5, opacity:0, scale:0.5});
    
  2. To make things easier to read, add some lines breaks:

    gsap.from('h2', {
       scrollTrigger:{}, duration:5, opacity:0, scale:0.5
    });
    
  3. Now add a line break inside the scrollTrigger object (and one before duration):

    gsap.from('h2', {
       scrollTrigger:{
    
       },
       duration:5, opacity:0, scale:0.5
    });
    
  4. Put the 'h2' trigger back in, and add a new toggleAction property:

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

    What are toggleActions?

    From the GSAP Docs greensock.com/docs/v3/Plugins/ScrollTrigger

    toggleActions: Determines how the linked animation is controlled at the 4 distinct toggle places—onEnter, onLeave, onEnterBack, and onLeaveBack, in that order. The default is 'play none none none'.

    So toggleActions: 'play pause resume reset' will play the animation when entering, pause it when leaving, resume it when entering again backwards, and reset (rewind back to the beginning) when scrolling all the way back past the beginning.

  5. Save and reload the page in Chrome.

    toggleActions control what happen when the animation leaves and enters the viewport from the top and bottom of the window. We just set onEnter (when the element comes into view from the bottom) to restart.

    • Scroll down and when the animation enters the window it should start to animate.
    • Keep scrolling so the heading scrolls off the top of the window and then bring it back into view to see it does not animate again.
    • Scroll up so the heading goes down off the bottom of the window.
    • Scroll back down to see the animation restarts (what our code says) every time the headings enters the window from the bottom.
  6. Set the second toggleAction to pause:

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

    We just set onLeave (when the element scrolls off the top of the window) to pause.

    • Scroll down so the heading starts animating, but keep scrolling so the heading goes off the top of the screen before it’s done animating.
    • When the heading leaves the top of the screen it will pause.
    • Bring the heading back down into view and notice the animation is still paused.
  8. Set the third toggleAction to resume:

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

    We just set onEnterBack (when the element scrolls into view coming down from the top of the window) to resume.

    • Scroll down so the heading starts animating, but keep scrolling so the heading goes off the top of the screen before it’s done animating.
    • When the heading leaves the top of the screen it will pause.
    • Bring the heading back down into the view and notice the animation will now resume where it left off.
  10. Ctrl–click (Mac) or Right–click (Windows) on the heading we’re animating and choose Inspect.
  11. As you bring the heading into view from the bottom of the window notice in the DevTools some code will have a colored highlight and changes as it animates.

    Once the animate is done, the colored highlight goes away. This is how we know when GSAP is animating something.

    Trigger the animation again but quickly move the heading back down off the bottom of the screen and notice in the DevTools that the animation continues, even though it’s offscreen. It’s not ideal performance to be animating something that you can’t see. Let’s fix that next.

  12. Now set the last toggleAction to pause:

    scrollTrigger:{
       trigger:'h2',
       toggleActions:'restart pause resume pause'
    }
    
  13. Save and reload the page in Chrome.

    We just set onLeaveBack (when the element scrolls off the bottom of the window) to pause.

    • Scroll down so the heading starts animating, but quickly scroll back up so the heading moves down off screen while it’s still animating.
    • Notice in the DevTools that the colored highlight stops, indicating GSAP has paused the animation. For performance, it’s better to stop the animation when it’s not onscreen.

Turning on Markers

Let’s tell GSAP to show some markers so we can better understand what’s going on.

  1. Add markers (don’t miss the comma on the line above):

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

    • At the bottom right there’s scroller-start and at the top right there’s scroller-end.
    • As you scroll, when start meets the scroller-start the animation starts.
    • We’ll see how scroller-end works in a moment.

Scrubbing: Linking an Animation to the Scrollbar

  1. Turn on scrubbing (don’t miss the comma):

    scrollTrigger:{
       trigger:'h2',
       toggleActions:'restart pause resume pause',
       markers:true,
       scrub:true
    },
    
  2. Delete the toggleActions and duration as they are no longer need:

    gsap.from('h2', {
       scrollTrigger:{
          trigger:'h2',
          markers:true,
          scrub:true
       },
       opacity:0, scale:0.5
    });
    
  3. Save and reload the page in Chrome.

    • Notice as you scroll through, the animation is tied to the scrollbar. So when you drag down or back up, it’s playing forward or reverse through the animation. Nice!
    • The animation starts at the bottom of the window and continues all the way to the top of the window, so we barely see the completed animation.

Starting & Ending Scroll Positions

  1. Add start and end positions (don’t miss the comma):

    scrollTrigger:{
       trigger:'h2',
       markers:true,
       scrub:true,
       start:'top 80%',
       end:'bottom 20%'
    },
    
    • The first value is the position relative to the element being animated.
      The second value is the position relative to the top of the scroller/viewport.

    • In this example the animation will start when the top of the heading hits 80% down from the top of the window, and it will end when the bottom of the heading hits 20% down from the top of the window.

    You can use: top, center, bottom, pixels, or percentages (always relative to the top).

  2. Save and reload the page in Chrome and notice the following:

    • The scroller-start is 80% down from the top of the window.
      The scroller-end is 20% down from the top.

    • As you scroll, when start meets the scroller-start the animation will start.
      When end meets the scroller-end the animation have ended.

    • Scrubbing can cause the animation to be a bit harsh or jerky at times, so let’s smooth things out by adding a time for scrub.

  3. Change the scrub value to 2 (seconds):

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

    Notice when you drag it will take 2 seconds to catch up to the scrollbar, smoothing out the animation. Smooth!

  5. Now that we’re done, delete the markers:

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

    Enjoy the final scrolling animation!

TIP: This example added scrollTrigger to a single tween, but for more complicated animations it can also be added to a gsap.timeline() where we’ve put the repeat property in previous exercises.

Learn more about ScrollTrigger in the GSAP Docs at greensock.com/docs/Plugins/ScrollTrigger

photo of Dan Rodney

Dan Rodney

Dan Rodney has been a designer and web developer for over 20 years. He creates coursework for Noble Desktop and teaches classes. In his spare time Dan also writes scripts for InDesign (Make Book JacketProper Fraction Pro, and more). Dan teaches just about anything web, video, or print related: HTML, CSS, JavaScript, Figma, Adobe XD, After Effects, Premiere Pro, Photoshop, Illustrator, InDesign, and more.

More articles by Dan Rodney

How to Learn JavaScript

Master JavaScript with hands-on training. JavaScript is one of the world's most widely-used coding languages. Learn JavaScript and its libraries to start creating interactive websites and mobile apps.

Yelp Facebook LinkedIn YouTube Twitter Instagram