Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
amit95

GSAP ScrollTrigger animations not working with Locomotive JS (until window is resized)

Go to solution Solved by akapowl,

Recommended Posts

I have sections across my site which are using ScrollTrigger. Once I implemented Locomotive JS, all of my ScrollTrigger animations stopped working.

 

I've read through the forums and saw that you need to update() ScrollTrigger when Locomotive is scrolling. I implemented this and saw no results.

 

Then, I resized the window and my ScrollTrigger animations that were in view, they started working.

 

In short, animations trigger on resize, but not on page load.

 

I've implemented update() and also tried refresh(), but no luck.

 

Below is a demo of the issue. Further down, I've added in steps to recreate and also a visual.

 

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<link href="https://cdn.jsdelivr.net/npm/locomotive-scroll@4.1.3/dist/locomotive-scroll.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/npm/locomotive-scroll@4.1.3/dist/locomotive-scroll.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/ScrollTrigger.min.js"></script>

<div data-scroll-container>
  <div data-scroll-section>

    <section class="hero">
      <div class="container">
        <div class="row justify-content-center justify-content-xl-between">
          <div class="col-12 col-md-10 col-lg-9 col-xl-5">
            <div class="hero__text text-center text-xl-start">
              <h1 class="hero__title" data-scroll data-scroll-speed="2">Title</h1>
            </div>
          </div>
        </div>
      </div>
    </section>

    <section class="textImageRepeater">
      <div class="container">
        <div class="row">
          <div class="col-12">

            <div class="textImageRepeater__item textImageRepeater__layout--row">
              <div class="textImageRepeater__text text-center text-md-start gsap_reveal gsap_reveal--fromRight">
                <div class="textImageRepeater__copy">
                  <h2>Header</h2>
                  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
                </div>
              </div>
              <div class="textImageRepeater__graphic text-center gsap_reveal gsap_reveal--fromLeft">
                <img class="textImageRepeater__image" src="https://picsum.photos/200/300" alt="placeholder-image" loading="lazy">
              </div>
            </div>

            <div class="textImageRepeater__item textImageRepeater__layout--rowReverse">
              <div class="textImageRepeater__text text-center text-md-start gsap_reveal gsap_reveal--fromRight">
                <div class="textImageRepeater__copy">
                  <h2>Header</h2>
                  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
                </div>
              </div>
              <div class="textImageRepeater__graphic text-center gsap_reveal gsap_reveal--fromLeft">
                <img class="textImageRepeater__image" src="https://picsum.photos/200/300" alt="placeholder-image" loading="lazy">
              </div>
            </div>

          </div>
        </div>
      </div>
    </section>

  </div>
</div>
$(function() {

  gsap.registerPlugin(ScrollTrigger);

  function animateFrom(elem, direction) {
    direction = direction || 1;

    var x = 0, y = direction * 100;
    if(elem.classList.contains("gsap_reveal--fromLeft")) {
      x = -100;
      y = 0;
    } else if (elem.classList.contains("gsap_reveal--fromRight")) {
      x = 100;
      y = 0;
    }

    elem.style.transform = "translate(" + x + "px, " + y + "px)";
    elem.style.opacity = "0";

    gsap.fromTo(elem, { x: x, y: y, autoAlpha: 0 }, {
      duration: 2,
      x: 0,
      y: 0,
      autoAlpha: 1,
      ease: "expo",
      overwrite: "auto"
    });

  }

  function hide(elem) {
    gsap.set(elem, { autoAlpha: 0 });
  }

  gsap.utils.toArray(".gsap_reveal").forEach(function(elem) {
    hide(elem); // assure that the element is hidden when scrolled into view
    ScrollTrigger.create({
      trigger: elem,
      onEnter: function() { animateFrom(elem) },
      onEnterBack: function() { animateFrom(elem, -1) },
      onLeave: function() { hide(elem) } // assure that the element is hidden when scrolled into view
    });
  });

  /*******************************************************************/
  /* Locomotive
  /*******************************************************************/

    const pageContainer = document.querySelector("[data-scroll-container]");

    const scroll = new LocomotiveScroll({
      el: pageContainer,
      smooth: true
    });


    // each time locomotive Scroll updates, tell ScrollTrigger to update too (sync positioning)
    scroll.on(pageContainer, ScrollTrigger.update);

    // tell ScrollTrigger to use these proxy methods for the ".data-scroll-container" element since Locomotive Scroll is hijacking things
    ScrollTrigger.scrollerProxy(pageContainer, {
      scrollTop(value) {
        return arguments.length ? scroll.scrollTo(value, 0, 0) : scroll.scroll.instance.scroll.y;
      }, // we don't have to define a scrollLeft because we're only scrolling vertically.
      getBoundingClientRect() {
        return {top: 0, left: 0, width: window.innerWidth, height: window.innerHeight};
      }
    });

    window.addEventListener("load", function (event) {
      ScrollTrigger.refresh();
    });

    ScrollTrigger.addEventListener("refresh", () => scroll.update());
    ScrollTrigger.refresh();


});
.hero {
  min-height: 1000px;
  background: lightblue;
  display: flex;
  align-items: center;
}

.textImageRepeater {
  overflow: hidden;
  padding: 120px 0 160px 0;
}
.textImageRepeater__intro {
  margin-bottom: 66px;
}
.textImageRepeater__layout--row {
  flex-direction: row !important;
}
.textImageRepeater__layout--rowReverse {
  flex-direction: row-reverse !important;
}
.textImageRepeater__item {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  padding-top: 70px;
  justify-content: space-between;
}
.textImageRepeater__header {
  margin: 17px 0;
}
.textImageRepeater__graphic {
  margin: 0;
}
.textImageRepeater__text, .textImageRepeater__graphic {
  flex-basis: 50%;
}
.textImageRepeater__text {
  max-width: 500px;
}

.c-scrollbar_thumb{
  background-color: #5D209F!important;
  width: 7px;
  margin: 2px;
  opacity: 1;
  border-radius: unset;
  mix-blend-mode: multiply;
}

 

Steps to recreate:

 

  1. Open this fiddle
  2. Widen the output box to something wide (i.e. 1300px)
  3. Run the fiddle
  4. Scroll down and you'll see the elements not loading
  5. Resize the output box to something smaller
  6. The scrollTrigger animations now appear

 

Here is a gif showcasing the issue:

 

demo.gif.0f1487539935ba160f4e566d02633443.gif

Link to comment
Share on other sites

  • Solution

Hello and welcome to the GSAP forums @amit95

 

It looks like you are creating your ScrollTriggers before even initializing locomotive-scroll. Take a look on the order of execution in the locomotive-scroll example on the .scrollerProxy() documentation page - you'll want to stick to that order for setting things up appropriately to begin with.

 

Also it looks like you did not specify the scroller on your ScrollTriggers. That's another thing you'll want to do, for things to properly get communicated between locomotive-scroll and ScrollTrigger. 

 

Hope that'll help get things running for you.

 

See the Pen zYrELYe by GreenSock (@GreenSock) on CodePen

 

  • Like 3
Link to comment
Share on other sites

Hi @akapowl,

 

Thanks for the guidance :) I've managed to make some headway after your suggestions and have somewhat of a solution in place. See latest fiddle here. For visual, here is my latest JS:

 

$(function() {

  const pageContainer = document.querySelector("[data-scroll-container]");

  const scroll = new LocomotiveScroll({
    el: pageContainer,
    smooth: true,
  });

  scroll.on(pageContainer, ScrollTrigger.update);

  ScrollTrigger.scrollerProxy(pageContainer, {
    scrollTop(value) {
      return arguments.length ? scroll.scrollTo(value, 0, 0) : scroll.scroll.instance.scroll.y;
    },
    getBoundingClientRect() {
      return {
        top: 0,
        left: 0,
        width: window.innerWidth,
        height: window.innerHeight
      };
    }
  });

  /* anims */

  function animateFrom(elem, direction) {
    direction = direction || 1;

    var x = 0,
      y = direction * 100;
    if (elem.classList.contains("gsap_reveal--fromLeft")) {
      x = -100;
      y = 0;
    } else if (elem.classList.contains("gsap_reveal--fromRight")) {
      x = 100;
      y = 0;
    }

    elem.style.transform = "translate(" + x + "px, " + y + "px)";
    elem.style.opacity = "0";

    gsap.fromTo(elem, {
      x: x,
      y: y,
      autoAlpha: 0
    }, {
      duration: 2,
      x: 0,
      y: 0,
      autoAlpha: 1,
      ease: "expo",
      overwrite: "auto",
    });

  }

  function hide(elem) {
    gsap.set(elem, {
      autoAlpha: 0
    });
  }

  gsap.utils.toArray(".gsap_reveal").forEach(function(elem) {
    hide(elem); // assure that the element is hidden when scrolled into view
    ScrollTrigger.create({
      trigger: elem,
      scroller: "[data-scroll-container]",
      onEnter: function() {
        animateFrom(elem)
      },
      onEnterBack: function() {
        animateFrom(elem, -1)
      },
      once: true,
    });
  });


  /* anims end */

  window.addEventListener("load", function(event) {
    ScrollTrigger.refresh();
  });


  ScrollTrigger.addEventListener("refresh", () => scroll.update());
  ScrollTrigger.refresh();

});

Key changes in the above based on before:

  • Moved my animateFrom() below the scrollerProxy()
  • Added scroller: "[data-scroll-container]" to my scrollTrigger

Follow-up question. Whilst I do have something working now, I have all of my GSAP animations in another js file. This file is called animations.js. In my demo above and in the fiddle, the scrollTrigger animations only work when the scrollTrigger is below the scrollerProxy() and above the scroll.update() event listener. 

 

Is the only way for this to work is to have all of my animations between the two? Something like below:

 

ScrollTrigger.scrollerProxy(pageContainer, {
  scrollTop(value) {
    return arguments.length ? scroll.scrollTo(value, 0, 0) : scroll.scroll.instance.scroll.y;
  },
  getBoundingClientRect() {
    return {
      top: 0,
      left: 0,
      width: window.innerWidth,
      height: window.innerHeight
    };
  }
});


/* 
/* ALL scrollTrigger animations here 
*/

window.addEventListener("load", function(event) {
  ScrollTrigger.refresh();
});

ScrollTrigger.addEventListener("refresh", () => scroll.update());
ScrollTrigger.refresh();

 

 

Link to comment
Share on other sites

I think the order is rather important for it to work.

 

I'm not sure about the environment you are working in, but technically you should be able to keep the setup of your animations in a different file. You could wrap those ScrollTrigger related animations in that file in a function and just call that function in the appropriate spot then maybe.

  • Like 3
Link to comment
Share on other sites

Fair enough, thanks for your guidance :)

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×