Horizontal Scrolling Section with Pin and Fade Effects

8.22.2024
by
Web Bae

In this tutorial, we’ll build a pin and fade effect using GSAP's ScrollTrigger plugin. This effect is commonly used for interactive, dynamic scrolling sections where the content is "pinned" in place for a moment before fading out, while the next section fades in and slides into view.

DEMO/CLONE
CODE
TUTORIAL

See the Pen Splide Slider by learyjk (@learyjk) on CodePen.

Step 1: Import GSAP and ScrollTrigger

The first step is to bring in the required libraries. We're using GSAP and its ScrollTrigger plugin, which allows us to create scroll-based animations.

import gsap from "https://cdn.skypack.dev/gsap";
import { ScrollTrigger } from "https://cdn.skypack.dev/gsap/ScrollTrigger";

// Register the ScrollTrigger plugin
gsap.registerPlugin(ScrollTrigger);

This imports the GSAP animation library from a CDN and registers the ScrollTrigger plugin, which enables us to trigger animations based on scroll position.

Step 2: HTML Structure

Before diving into the code, let’s assume you have an HTML structure like this:

<div id="horizontal-section">
  <div class="wrapper">
    <div class="item">Item 1</div>
    <div class="item">Item 2</div>
    <div class="item">Item 3</div>
  </div>
</div>

Here, the #horizontal-section contains a wrapper that holds multiple item elements. These items will be animated as we scroll.

Step 3: Setting Initial States for Items

We want all items except the first one to be positioned outside the viewport, so they slide into view when triggered. We use GSAP's set function to place each item 100% off-screen (to the right) except for the first one.

// Select the HTML elements needed for the animation
const horizontalSection = document.querySelector("#horizontal-section");
const wrapper = horizontalSection.querySelector(".wrapper");
const items = wrapper.querySelectorAll(".item");

// Set initial positions of items
items.forEach((item, index) => {
  if (index !== 0) {
    gsap.set(item, { xPercent: 100 });
  }
});
  • gsap.set: This method sets the initial position of each item. In this case, every item except the first is moved 100% off-screen to the right using xPercent: 100.

Step 4: Creating the Pin and Fade Animation with GSAP Timeline

Now, we create a timeline to control the animation of the items as the user scrolls. Each item will fade out and shrink slightly in size, while the next item fades in and slides into view.

function initScroll() {
  const tl = gsap.timeline({
    scrollTrigger: {
      trigger: horizontalSection,
      pin: true,
      start: "top top",
      end: () => `+=${items.length * 100}%`,
      scrub: 1,
      invalidateOnRefresh: true,
    },
    defaults: { ease: "none" },
  });
  
  // Animate each item
  items.forEach((item, index) => {
    if (index !== items.length - 1) {
      tl.to(item, {
        scale: 0.9,
        opacity: 0,
      }).to(
        items[index + 1],
        {
          xPercent: 0,
        },
        "<"
      );
    }
  });
}

Breaking Down the Code:

  1. GSAP Timeline:
    • We create a timeline tl to manage a series of animations in sequence.
    • This timeline is connected to ScrollTrigger, which controls the progress of the animations based on the user’s scroll position.
  2. ScrollTrigger Properties:
    • trigger: The element that will trigger the scroll animation (in this case, #horizontal-section).
    • pin: true: This keeps the section in place while its contents animate. The content will scroll inside this pinned section.
    • start: "top top": The animation starts when the top of the section reaches the top of the viewport.
    • end: +=${items.length * 100}%``: The animation ends after scrolling through all items. The 100% is a relative measure based on the height of the viewport, so this ensures that the animation lasts long enough for all items to fade in and out.
    • scrub: 1: This creates a smooth, synchronized relationship between the scroll position and the timeline, ensuring that the animations respond to how quickly or slowly the user scrolls.
    • invalidateOnRefresh: true: Ensures the ScrollTrigger recalculates its start and end positions if the window is resized.
  3. Animating Items:
    • Inside the forEach loop, we animate each item in sequence.
    • The scale is reduced to 0.9 and the opacity is faded to 0, making the item shrink and disappear.
    • At the same time, the next item is animated by setting xPercent: 0, bringing it into the viewport from its initial off-screen position.
    • The "<" sign tells GSAP to execute the second animation at the same time as the first one (i.e., while the previous item is fading out, the next one is sliding in).

Step 5: Initialize the Scroll Animations

Finally, we call the initScroll function to activate the animations.

// Call the function
initScroll();

This runs the timeline and enables the pinning, fading, and sliding effects for your items as you scroll through the section.

Step 6: Customizing the Effects

You can easily tweak this setup for different effects. For example, you could:

  • Adjust the scale value to control how much the item shrinks.
  • Change the opacity values to create different fade speeds.
  • Modify the timeline duration by adjusting the percentage in the end property of ScrollTrigger.
  • Add more effects like rotation, blur, or color change during the transitions.

Conclusion

This pin and fade effect is a powerful technique for building smooth, engaging scroll animations. By pinning the section and fading out the current item while sliding the next one in, you can create a seamless transition between content blocks that guides users through your content in an interactive and dynamic way.

With GSAP and ScrollTrigger, the possibilities are endless. These libraries make it easy to animate elements based on scroll position, opening up creative opportunities to enhance user engagement on your website.

Feel free to adjust the values and experiment with different effects to suit your design needs!