Jump to content
Search Community

GSAP ScrollTrigger issue on page change

PixeledCode test
Moderator Tag

Go to solution Solved by OSUblake,

Recommended Posts

Hi, I'm trying to implement a basic ScrollTrigger animation on Nextjs. It's basically changing sidebar background based on current position of scroll. You can check it's implementation here: Introduction - Budget Basics | Open Budgets India

Problem is initial load of page, which messes up the the start/end of scrolltrigger but resizing the browser fixes the position. I tried some solutions from this post: ScrollTrigger Unexpected Behavior with Smooth Scrollbar in React/NextJs - GSAP - GreenSock but they are not working in my case.

 

All of the code is available here: budget-basic-next/[chapter].js at main · PixeledCode/budget-basic-next (github.com) but basically what I'm doing is

 

 useEffect(() => {

        gsap.registerPlugin(ScrollTrigger)
        setTimeout(handleSidebarAnimation, 100)



        return () => {

            ScrollTrigger.refresh()
            if (ScrollTrigger.getById('st-id')) {
                ScrollTrigger.getById('st-id').kill()
            }
        }
    }, [])

and the function is 

 

function handleSidebarAnimation() {
    const articles = gsap.utils.toArray('article')

    articles.forEach((article) => {
        let sideLink = document.querySelector(
            `li[keyid=${article.getAttribute('id')}]`
        )
        gsap.to(sideLink, {
            scrollTrigger: {
                markers: true,
                trigger: article,
                id: 'st-id',
                start: 'top 22%',
                end: 'bottom 18%',
                refreshPriority: 1,
                toggleActions: 'restart complete reverse reset',
                onEnter() {
                    sideLink.classList.add('activeSidebar')
                },
                onLeave() {
                    sideLink.classList.remove('activeSidebar')
                },
                onEnterBack() {
                    sideLink.classList.add('activeSidebar')
                },
                onLeaveBack() {
                    sideLink.classList.remove('activeSidebar')
                },
            },
        })
    })
}

 

I know I'm probably doing something wrong and it's dom order which is creating issues on initial load (eg: coming from home page to the page with sidebar and animation.) but I am not able to find where. Any help is appreciated!

Link to comment
Share on other sites

Hi @Cassie thanks for replying. So I tried to setup and here is the codesandbox link: mystifying-nash-pp4kd - CodeSandbox

I was testing and noticed something. The problem is not on the pages without images and so I believe that the images are being loaded late and then the ScrollTrigger is not refreshing on that change... Could this be an issue, and if yes, any idea on how to fix it?

 

Thank You

Link to comment
Share on other sites

58 minutes ago, PixeledCode said:

Hi @Cassie thanks for replying. So I tried to setup but wasn't able to import css files, I'm ashamed. Here is the codesandbox link: mystifying-nash-pp4kd - CodeSandbox

Anyway, I was testing and noticed something. The problem is not on the pages without images and so I believe that the images are being loaded late and then the ScrollTrigger is not refreshing on that change... Could this be an issue, and if yes, any idea on how to fix it?

 

Thank You

ok so this post helped. ScrollTrigger doesn't work properly on page with lazy load images - GSAP - GreenSock. I'm listening to images being loaded and then refreshing now. 

 

Fixing this I found another issue. Next.js have next/link for routing which makes routing possible without reloading. Kind of hot reloading but that also crashes gsap. You can possibly reproduce it by going to the link https://pp4kd-3001.sse.codesandbox.io and selecting first box 'Introduction', go to the bottom and selecting, 'read more'. Next page will be broken with total height similar to previous page but all of it is whitespace.

 

Either removing scrolltrigger or removing next/link and using regular <a> tags fixes it.

Link to comment
Share on other sites

19 minutes ago, OSUblake said:

Hi @PixeledCode

 

You codesandbox link isn't working, it's show a 502 error. Can you provide another one?

 

 

Hi, sorry about that. That was production mode build I made on Codesandbox, I think they don't keep them running for long. Here's the code: https://codesandbox.io/s/mystifying-nash-pp4kd?file=/pages/_app.js

Link to comment
Share on other sites

I'm having trouble understanding how your app even works, and it's really slow to navigate, but it looks like it you're not creating new scroll triggers when going to a different page.

 

I added a line to log out the number of scroll triggers, but it only fires once.

function handleSidebarAnimation() {
  console.log("TRIGGERS 1", ScrollTrigger.getAll().length);

  ...
}

 

And the cleanup never fires.

useEffect(() => {
    setTimeout(handleSidebarAnimation, 100);

    window.addEventListener("scroll", handleScroll);
    return () => {
      const t = ScrollTrigger.getAll();
      console.log("TRIGGERS 2", t.length);
      t.forEach((t) => t.kill());
      window.removeEventListener("scroll", handleScroll);
    };
  }, []);

 

So that means ScrollTrigger doesn't know the new layout. You need to find a way to recreate your triggers on a new page, and kill the old ones.

 

I would also use v3.6.1 for the time being as we are investigating a possible issue when navigating pages.

 

I would also avoid using setTimeout as something could change in between that time period. If you need ScrollTrigger to recalculate, just use .refresh().

 

 

 

  • Like 1
Link to comment
Share on other sites

15 minutes ago, OSUblake said:

I'm having trouble understanding how your app even works, and it's really slow to navigate, but it looks like it you're not creating new scroll triggers when going to a different page.

 

I added a line to log out the number of scroll triggers, but it only fires once.


function handleSidebarAnimation() {
  console.log("TRIGGERS 1", ScrollTrigger.getAll().length);

  ...
}

 

And the cleanup never fires.


useEffect(() => {
    setTimeout(handleSidebarAnimation, 100);

    window.addEventListener("scroll", handleScroll);
    return () => {
      const t = ScrollTrigger.getAll();
      console.log("TRIGGERS 2", t.length);
      t.forEach((t) => t.kill());
      window.removeEventListener("scroll", handleScroll);
    };
  }, []);

 

So that means ScrollTrigger doesn't know the new layout. You need to find a way to recreate your triggers on a new page, and kill the old ones.

 

I would also use v3.6.1 for the time being as we are investigating a possible issue when navigating pages.

 

I would also avoid using setTimeout as something could change in between that time period. If you need ScrollTrigger to recalculate, just use .refresh().

 

 

 

Thank you for this. My problem looks similar to the post you shared. Using normal <a> instead of next/link is working fine. I'll also try with v3.6.1 and see how it goes.

And yeah, sorry for slow speed. I connected it with my strapi backend which is hosted on a really slow server so it's taking time for each navigation.

  • Like 1
Link to comment
Share on other sites

17 minutes ago, PixeledCode said:

Using normal <a> instead of next/link is working fine

 

I'm not familiar with how next/link works, but it sounds like it's just reusing the same component instance instead of making a new one, which is why the useEffect only fires once. Not sure if there is way to disable that behavior. I know with Nuxt, Vue's version of Next, there is.

 

  • 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.
×
×
  • Create New...