Consecutive Scroll Animations with One Element

A simple concept of animating one element across different waypoints on scroll using GSAP Flip and ScrollTrigger.

Ivan Gorbunov designed a beautiful concept a while ago where this one element gets animated throughout different layouts:

This made me wonder how simple it would be to animate an element across various waypoints while scrolling, making it adapt to the spots using GSAP’s Flip.

It turns out there’s a very helpful GSAP demo that demonstrates this perfectly: GSAP ScrollTrigger Consecutive Scrub Flips. So this is basically showing how to create a consecutive flip animation with ScrollTrigger and scrubbing.

See the Pen GSAP ScrollTrigger Consecutive Scrub Flips by GSAP (@GreenSock) on CodePen.

I went ahead and created a little demo with a fancier look, so here is an exploration of that concept.

In our HTML we set the main element to be a div with class “one”:

<section class="content content--inital">
  <div class="one" style="background-image:url(img/main.jpg)"></div>
</section>

In the consecutive sections we define a placeholder element (“content__img”) and style the layout with that element in mind. We also give that element a data-attribute called “data-step” which will serve as indicator that this is an element we want to use as waypoint in our JavaScript:

<section class="content content--center content--blend">
  <div data-step class="content__img"></div>
  <h1 class="content__title font-alt"><span>Seraph</span><br><span>Kamos</span></h1> 
</section>
// Create a GSAP timeline with ScrollTrigger for the Flip animation
const tl = gsap.timeline({
  scrollTrigger: {
    trigger: parentElement, // Trigger animation based on the parent element
    start: 'clamp(center center)', // Start animation when parent is in the center of the viewport
    endTrigger: stepElements[stepElements.length - 1], // End at the last step element
    end: 'clamp(center center)', // End animation when the last step is centered
    scrub: true, // Synchronize animation with scroll
    immediateRender: false
  }
});
// Add Flip animations to the timeline for each state
states.forEach((state, index) => {
  const customFlipConfig = {
    ...flipConfig,
    ease: index === 0 ? 'none' : flipConfig.ease // Use 'none' easing for the first step
  };
  tl.add(Flip.fit(oneElement, state, customFlipConfig), index ? '+=0.5' : 0);
});

Check out the code for the other bits and have fun exploring and playing around with this!

Thanks for checking by!

Manoela Ilic

Manoela is the main tinkerer at Codrops. With a background in coding and passion for all things design, she creates web experiments and keeps frontend professionals informed about the latest trends.

Stay in the loop: Get your dose of frontend twice a week

Fresh news, inspo, code demos, and UI animations—zero fluff, all quality. Make your Mondays and Thursdays creative!