Jump to content
GreenSock

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

scrollTrigger marker positions shift position, animation sometimes starts off screen

Go to solution Solved by katokalen,

Recommended Posts

Hi there,

 

I'm running into weirdness with scrollTrigger and marker positioning. I have a page with 2 components built in Next.js, one is using scrollTrigger to pin an element for a duration (AnimationScrollBlock), and another component fades in some images when the user scrolls to it (ImagesBlock).

 

When I click between navigation pages and then back to the "Case" page, sometimes the markers seem to be in the correct position, sometimes they aren't. The same thing appears to happen when I do a hard refresh on the page. Sometimes they are correct, other times they aren't. When they aren't in the correct position the animation for the fading images has already completed before I actually get to that section of the screen.

 

Here is a url to see the issue in action: https://3qfnr.sse.codesandbox.io/case

Try doing a hard refresh on the page and see if the marker position for images-1 and images-2 move around. Click to another page and then back to see if the markers move.

 

Screenshot below as well showing what I see when the position is calculated incorrectly and correctly.

 

And here is the codesandbox link to see the code: https://codesandbox.io/s/eager-banach-3qfnr (click on the Case Study link in the nav)

 

As a test, when I move the AnimationScrollBlock component to be underneath the ImagesBlock component, things work as expected. 

 

I'm sure it's something dumb but I'm stumped, would really appreciate any insight you might have! Thank you!

 

correct-markers-1.png

incorrect-markers-1.png

Link to comment
Share on other sites

Hey katokalen and welcome to the GreenSock forums. Thanks for supporting GreenSock with a Club GreenSock membership!

 

I haven't looked at the code yet. Have you read through the most common ScrollTrigger mistakes article?

Link to comment
Share on other sites

Yes I have. I also have been scouring the greensock forums for tips & tricks with React hooks and making sure to register my scroll trigger instances, kill them on unmount, and also try to refresh them to get the correct values. The forum has been a great help but now wondering if it’s something in my actual pinning animation or a missing CSS spacer that  might be the problem? 
 

Looking forward to your insight once you’ve looked at my minimal demo. 

Link to comment
Share on other sites

Sorry for the delayed response - the weekend :) 

 

This mis-position is due to the components in the AnimationScrollBlock not being loaded before the ScrollTriggers are set up. It's one of the most common ScrollTrigger mistakes that I linked to. You can see that this is the issue by resizing the window after the page has loaded incorrectly - that forces ScrollTrigger to refresh and the position is corrected. So if you call ScrollTrigger.refresh() after the components have been switched out after the page change the issue will go away. 

 

Side notes:

  • toggleActions don't do anything if you have a scrub applied so you can remove that when applicable.
  • ease: "power4.inout" should be ease: "power4.inOut".
  • Since you already have a variable reference to your timeline, you could use that to kill off the ScrollTrigger instead of .getById().
  • You have multiple gsap.registerPlugin(ScrollTrigger); per file. It's better to just include it once if the window exists.
  • It's best to stick to .to() and .from() if you don't need the functionality of .fromTo().
  • It might make more sense to use ScrollTrigger's .batch() functionality for your images so that you can do some staggering reveals.
  • Like 1
Link to comment
Share on other sites

Quote

So if you call ScrollTrigger.refresh() after the components have been switched out after the page change the issue will go away. 

 

Thanks Zach, so just to be clear, I should be calling ScrollTrigger.refresh() on unMount inside of my UseEffect for each component? Or where do I add this exactly?

 

So like this?
 

  useEffect(() => {

    let c1 = gsap.timeline({
      scrollTrigger: {
        id: "screen",
        trigger: trigger.current,
        pin: wrapper.current,
        scrub: 1,
        markers: true,
        start: "top top"
      }
    });

    c1.to(img1.current, {
      duration: 2,
      yPercent: -70,
      ease: "power4.inOut"
    });

    // Need to unmount these
    return () => {

     ScrollTrigger.refresh(); // New Line
      c1.kill();
    };
  }, []);

 

I can make these other adjustments, should the  gsap.registerPlugin(ScrollTrigger);be inside of _app.js, or the parent page where the components are imported (like case.js)?

 

Link to comment
Share on other sites

8 minutes ago, katokalen said:

just to be clear, I should be calling ScrollTrigger.refresh() on unMount inside of my UseEffect for each component? Or where do I add this exactly?

That's a React question and I don't know the answer to it. The goal is to have ScrollTrigger refresh once all of your components have mounted. Maybe @Rodrigo has some time to provide some insight at some point.

Link to comment
Share on other sites

Ok on my side I've made the quick adjustments you recommended in your first comment to my minimal demo (I will refactor the imagesBlock animation to use .batch() at a later date, thank you for that).

 

I've moved the registering ScrollTrigger check to the parent page (case.js) and removed it from the components. Not sure if you saw my question above about whether this needs to live inside _app.js or is this is fine in the parent page? I'll leave it in the parent page for now as it appears to be working.

 

I've added ScrollTrigger.refresh() to the parent page (case.js) inside its UseEffect instead of the components and this appears to have fixed the issue!

 

Thanks for the help, if Rodrigo has any feedback would love to hear it, otherwise I think this is working.

 

 

  • Like 1
Link to comment
Share on other sites

  • 3 months later...
  • Solution

Hi all - looping back on this. I pulled this back into my next.js app (using Contentful as the CMS) and I determined that the issue I was seeing was that my component would initialize, THEN the content from Contentful would pop in, and then the heights of my animations would be incorrect as they had already initialized. 

 

I couldn't find a good fix for this aside from reinitializing my animations after the content came in using setTimeout. But definitely seems to be more of a Next.js configuration issue then anything with GSAP. 

Link to comment
Share on other sites

6 hours ago, katokalen said:

I couldn't find a good fix for this aside from reinitializing my animations after the content came in using setTimeout. But definitely seems to be more of a Next.js configuration issue then anything with GSAP. 

 

You definitely should not have to use setTimeout. I'm assuming that that there must be some type of event/callback when your contentful stuff is loaded. You should definitely be hooking into that somehow.

 

  • Like 1
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.

×