Scroll Animation Made Easy: HTML, CSS, JS with GSAP ScrollTrigger


By Faraz -

Learn how to implement scroll-based animations effortlessly using GSAP and ScrollTrigger. HTML, CSS, and JavaScript guide included!

Scroll Animation Made Easy HTML, CSS, JS with GSAP ScrollTrigger.jpg

ScrollTrigger is a plugin of the GreenSock Animation Platform (GSAP), a powerful JavaScript library for creating high-performance animations. ScrollTrigger enables developers to trigger animations based on the scroll position, allowing for engaging and dynamic web experiences. In this tutorial, we'll explore how to utilize ScrollTrigger for captivating scroll animations on your website. Let's dive in!

Source Code

Step 1 (HTML Code):

Begin by structuring your HTML document with the necessary elements you intend to animate. Utilize div elements or other appropriate tags to encapsulate sections or elements to be animated.

Let's break down the structure and key elements:

1. <!DOCTYPE html>: This declaration specifies the document type and version of HTML being used, which is HTML5 in this case.

2. <html lang="en">: This tag represents the root element of the HTML document and specifies the language of the content, which is English in this case.

3. <head>: This section contains meta-information about the document, such as character encoding, viewport settings, title, and links to external resources like CSS files.

  • <meta charset="UTF-8">: Specifies the character encoding of the document as UTF-8, which supports a wide range of characters and languages.
  • <meta http-equiv="X-UA-Compatible" content="IE=edge">: Instructs Internet Explorer to use the latest rendering engine available.
  • <meta name="viewport" content="width=device-width, initial-scale=1.0">: Sets the viewport width to the device width and sets the initial zoom level to 1.0, ensuring proper scaling on different devices.
  • <title>GSAP Animate ScrollTrigger</title>: Defines the title of the webpage that appears in the browser tab.
  • <link rel="stylesheet" href="styles.css">: Links an external CSS file named "styles.css" to style the webpage.

4. <body>: This section contains the visible content of the webpage.

  • Within the body, there are several <div> elements representing different sections of the webpage.
  • The first <div> with class "loader" seems to be a loading animation displayed before the page content is fully loaded.
  • Following that, there's a <div> with class "demo-wrapper" containing various sections like header, text, and gallery.
  • Each section contains content wrapped in appropriate HTML tags such as <header>, <section>, <ul>, <li>, <img>, and <footer>.
  • Images within the <section class='demo-gallery'> elements are loaded from Unsplash using randomized URLs.
  • The footer contains a link to Unsplash as a credit for the images used.
  • Finally, there are several <script> tags at the end of the body, which include external JavaScript files and a custom script named "script.js" for handling animations and interactions using GSAP and ScrollTrigger.

Step 2 (CSS Code):

Apply CSS styles to your HTML elements to control their appearance and layout. CSS can be used to define initial states or styles for elements before they are animated, enhancing the overall visual presentation of your webpage

Let's break down the CSS Code:

1. :root { font-size: 16px }: Sets the base font size for the document to 16 pixels.

2. @media (max-width: 500px) { :root { font-size: 14px } }: Changes the base font size to 14 pixels when the viewport width is 500 pixels or less. This is a responsive design technique.

3. * { margin: 0; padding: 0; box-sizing: border-box; }: Applies margin and padding reset to all elements and sets the box-sizing property to border-box. This ensures that padding and border are included in the element's total width and height.

4. ::-moz-selection { background: #87cd33; color: white; } and ::selection { background: #87cd33; color: white; }: Styles the selected text in the webpage, setting the background to a light green color and the text color to white.

5. body { overflow: hidden; font-family: -apple-system, BlinkMacSystemFont, Segoe UI,Helvetica, Arial,sans-serif, Apple Color Emoji, Segoe UI Emoji; }: Styles the body of the webpage, setting the overflow to hidden and specifying a font stack for text rendering.

6. h1 { font-size: 5rem } and h2 { font-size: 2rem }: Sets the font sizes for heading elements.

7. img { width: 100%; height: auto; background: #f0f0f0; }: Styles images, making them responsive by setting the width to 100% of their container and maintaining the aspect ratio. Also, it sets a light gray background color for images.

8. ul { padding-left: 1rem; list-style: none; }: Styles unordered lists, removing the default list-style and adding left padding.

9. li { flex-shrink: 0; width: clamp(500px, 60vw, 800px); padding-right: 1rem; }: Styles list items, making them flexible in width using the clamp function, with a minimum width of 500px, a maximum width of 800px, and a fluid width between 60vw and 800px. Also, adds the right padding.

10. header {height: 100vh} and footer {height: 50vh}: Sets the heights of the header and footer to 100% and 50% of the viewport height respectively.

11. :-webkit-any-link, :-moz-any-link, and :any-link: Styles all types of links, setting the text color to a specific shade of green.

12. .df, .aic, and .jcc: Defines CSS classes for flexbox layout properties like display, align-items, and justify-content.

13. .loader and .demo-wrapper: Styles for specific classes used for layout and styling purposes.

14. .wrapper, .demo-gallery, and .demo-text .text: More styling for specific classes used in the webpage design.

:root { font-size: 16px }
@media (max-width: 500px) { :root { font-size: 14px } }

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;

::-moz-selection {
  background: #87cd33;
  color: white;

::selection {
  background: #87cd33;
  color: white;

body {
  overflow: hidden;
  font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;

h1 { font-size: 5rem }
h2 { font-size: 2rem }

img {
  width: 100%;
  height: auto;
  background: #f0f0f0;

ul {
  padding-left: 1rem;
  list-style: none;

li {
  flex-shrink: 0;
  width: clamp(500px, 60vw, 800px);
  padding-right: 1rem;

header {height: 100vh}
footer {height: 50vh}

:-webkit-any-link { color: #4e9815; }

:-moz-any-link { color: #4e9815; }

:any-link { color: #4e9815; }

.df {display: flex}
.aic {align-items: center}
.jcc {justify-content: center}

.loader {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: black;
  color: white;

.demo-wrapper {
  overflow-x: hidden;

.wrapper {
  display: flex;

.demo-gallery:not(.last) {
  padding-bottom: 1rem;

.demo-text .text {
  font-size: clamp(8rem, 15vw, 16rem);
  line-height: 1;
  font-weight: 900;

Step 3 (JavaScript Code):

Integrate GSAP and ScrollTrigger into your project by including the relevant JavaScript files. Initialize ScrollTrigger and define triggers based on scroll positions to initiate animations at desired points on the webpage.

This JavaScript code utilizes the GSAP (GreenSock Animation Platform) library along with ScrollTrigger plugin to create animations based on scrolling triggers. Let's break it down step by step:

1. gsap.registerPlugin(ScrollTrigger);: This line registers the ScrollTrigger plugin with GSAP, enabling the use of ScrollTrigger functionality.

2. onst images = gsap.utils.toArray('img');: It selects all img elements on the page and stores them in an array called images.

3. const loader = document.querySelector('.loader--text');: It selects an element with the class loader--text and assigns it to the loader constant. This element is presumably used to display loading progress.

4. const updateProgress = (instance) => loader.textContent = ${Math.round(instance.progressedCount * 100 / images.length)}%;: This is a function updateProgress which takes an instance parameter. It updates the text content of the loader element to show the loading progress as a percentage.

5. const showDemo = () => { ... }: This is a function showDemo which contains the logic to show the demo once all images are loaded.

6. document.body.style.overflow = 'auto';: It sets the CSS overflow property of the body element to auto, allowing scrolling.

7. document.scrollingElement.scrollTo(0, 0);: It scrolls the page to the top.

8. gsap.to(document.querySelector('.loader'), { autoAlpha: 0 });: It animates the opacity of the .loader element to 0, making it disappear.

9. gsap.utils.toArray('section').forEach((section, index) => { ... }: It selects all section elements on the page and iterates through them.

10. Inside the forEach loop:

  • const w = section.querySelector('.wrapper');: It selects an element with the class wrapper inside each section and assigns it to the constant w.
  • [x, xEnd] = index % 2 ? ['100%', (w.scrollWidth - section.offsetWidth) * -1] : [w.scrollWidth * -1, 0];: This line calculates the starting and ending positions for the animation based on the index of the section. If the index is even, it sets the starting position to w.scrollWidth * -1 and the ending position to 0, otherwise, it sets the starting position to 100% and the ending position to (w.scrollWidth - section.offsetWidth) * -1.
  • gsap.fromTo(w, { x }, { x: xEnd, scrollTrigger: { trigger: section, scrub: 0.5 } });: It animates the x property of the w element from the starting position to the ending position, triggered by scrolling the section. The scrub option defines the intensity of the scrubbing effect.

11. imagesLoaded(images).on('progress', updateProgress).on('always', showDemo);: It uses the imagesLoaded library to monitor the loading progress of images. When progress is made (progress event), it calls the updateProgress function. When all images are loaded (always event), it calls the showDemo function.


const images = gsap.utils.toArray('img');
const loader = document.querySelector('.loader--text');
const updateProgress = (instance) =>
loader.textContent = `${Math.round(instance.progressedCount * 100 / images.length)}%`;

const showDemo = () => {
  document.body.style.overflow = 'auto';
  document.scrollingElement.scrollTo(0, 0);
  gsap.to(document.querySelector('.loader'), { autoAlpha: 0 });

  gsap.utils.toArray('section').forEach((section, index) => {
    const w = section.querySelector('.wrapper');
    const [x, xEnd] = index % 2 ? ['100%', (w.scrollWidth - section.offsetWidth) * -1] : [w.scrollWidth * -1, 0];
    gsap.fromTo(w, { x }, {
      x: xEnd,
      scrollTrigger: {
        trigger: section,
        scrub: 0.5 } });


imagesLoaded(images).on('progress', updateProgress).on('always', showDemo);

Final Output:

Scroll Animation Made Easy HTML, CSS, JS with GSAP ScrollTrigger.gif


Congratulations! You've successfully implemented GSAP ScrollTrigger to create captivating scroll-based animations on your website. Experiment with different animation techniques and unleash your creativity to enhance user engagement and elevate the user experience. Happy animating!

Code by: Noel Delgado

That’s a wrap!

I hope you enjoyed this post. Now, with these examples, you can create your own amazing page.

Did you like it? Let me know in the comments below 🔥 and you can support me by buying me a coffee.

And don’t forget to sign up to our email newsletter so you can get useful content like this sent right to your inbox!

Faraz 😊

End of the article

Subscribe to my Newsletter

Get the latest posts delivered right to your inbox

Latest Post