Jump to content
Search Community

Parallax effect don't work after navigating between page links in next.js project.

Yunus Emre test
Moderator Tag

Recommended Posts

Hi everyone!

I'm scrolling images in different speeds (speed data comes from HTML's data-* attribute as you can see) and creat a parallax effect. The animation has no problem with working but sometimes it's not responding (all the images scrolling in the same speed) when coming back from other (about, works, contact etc.) pages. And sometimes it's working nonetheless.

None of other animations (with or without scrollTrigger) have this problem.

 

Is this more related with GSAP or Next.js?  Any help on this please?

 

export function Parallax({ children }) {
  const el = useRef()

  useEffect(() => {
    const animations = []
    const elements = gsap.utils.toArray(el.current.children)
    elements.forEach((element) => {
      const movement = -(element.offsetHeight * element.dataset.speed)
      const animation = gsap.timeline({
          scrollTrigger: {
            trigger: element,
            start: "top bottom",
            end: "bottom top",
            scrub: 0.2
          }
        })
        .to(element, {
          y: movement,
          ease: "none"
        }, 0)

      animations.push(animation)
    })

    return () => {
      animations.forEach((animation) => animation.scrollTrigger.kill())
    }
  }, [])

  return <div ref={el}>{children}</div>
}
Link to comment
Share on other sites

Is it because child elements (images) that has the data attributes is coming from server side and gsap animation try to fetch that speed data after mounting in client side?

Simply I used the Parallax component like this:

<Parallax>
  <div data-speed="0.2"><img src="/images/1-1.jpg"/></div>
  <div data-speed="0.2"><img src="/images/1-2.jpg"/></div>
  <div data-speed="0.2"><img src="/images/1-3.jpg"/></div>
  <div data-speed="0.7"><img src="/images/2-1.jpg"/></div>
  <div data-speed="0.6"><img src="/images/2-2.jpg"/></div>
  <div data-speed="0.5"><img src="/images/2-3.jpg"/></div>
</Parallax>

 

Link to comment
Share on other sites

It's really difficult to troubleshoot without a minimal demo - can you please provide one? 

 

It sounds like your code is running prematurely (or not at all). I'd recommend adding a console.log() in there to see if el.current.children is what you think it is at that time. Probably a lifecycle thing related to Next.js but I'm not very familiar with Next.js or React. I'm sure a minimal demo will help, perhaps in CodeSandbox.io - here's a starter template: https://codesandbox.io/s/gsap-nextjs-starter-jekrn

Link to comment
Share on other sites

I created a simple sandbox here:

https://codesandbox.io/s/headless-dream-riz9j?file=/styles/Index.css

I fetched and console log the speed data with no problem. gsap seem's don't use it appropriately.

 

Above I said it occurs sometimes and randomly but I now found "a case" that causes this problem.

I go linked about page > refresh about page > go back with using link > animation breaks.

 

Besides this,  in iOS;

even just refreshing the main page or navigating between pages sometimes can cause this issue.

Maybe it's about animations don't load in enough time and scrolling without waiting makes animations behave different.

 

Link to comment
Share on other sites

Yep, that looks like a Next.js lifecycle issue - if you log out each ScrollTrigger's end value, you'll notice they all match in the scenario you mentioned which tells me that ScrollTrigger did its calculations BEFORE your images loaded and affected the document flow.

 

ScrollTrigger automatically calls ScrollTrigger.refresh() when the page loads, on DOMContentLoaded, on resize, and when the tab gets unhidden. But it looks like your setup is dynamically loading things in and it's not a normal page load/refresh, thus you need to make sure you call ScrollTrigger.refresh() AFTER the document is in its final state (no more document reflow). Either do it after your images load or set those image elements to have an explicit height/width via CSS so that the page doesn't shift around after they load. 

  • Like 1
Link to comment
Share on other sites

Thanks for the answer! Setting images to have an explicit width/height did the job. But sizes can be changeable in the future. 

4 hours ago, GreenSock said:

thus you need to make sure you call ScrollTrigger.refresh() AFTER the document is in its final state (no more document reflow).

Sorry for my inexperience but I couldn't make it. Should I ask this part in another next.js related platform?

Link to comment
Share on other sites

4 hours ago, Yunus Emre said:

Thanks for the answer! Setting images to have an explicit width/height did the job. But sizes can be changeable in the future. 

 

You can refresh ScrollTrigger after an image loads.

<img onLoad={() => ScrollTrigger.refresh()} />

 

  • Like 3
Link to comment
Share on other sites

Hey @Yunus Emre I saw your demo and the problem is not from Gsap or Next, the issue is related with loading times.
If you set the network as "slow 3g" and you are on the home page, the images are loaded before your Javascript, so when your script runs the images have width and height. On the other hand if you are on about page and reload the site, your script is loaded without images, and then if you go to the home page the images aren't loaded because as they only exist on the home the browser needs to download them, that's the reason you have those random numbers.

I created a demo with the images on the about page, and if you go to the home the parallax is working fine.
https://codesandbox.io/s/jovial-paper-y21b7

As @OSUblake said, you need an onload function and run ScrollTrigger when the images are loaded. 

Hope this helps! 🤘
 

  • Like 4
Link to comment
Share on other sites

Thanks much for the explanation @nicofonseca! Now it made sense to me. But I couldn't figured out how to refreshing ScrollTrigger on element load.

in this demo

https://codesandbox.io/s/headless-dream-riz9j?file=/pages/index.js

I used it like 

<img onLoad={() => ScrollTrigger.refresh()} src="/images/1-1.jpg" />

 

And in the animation component I tried this;

element.onload = () => {
        ScrollTrigger.refresh();
      };

But it isn't working.

 

6 hours ago, nicofonseca said:

the issue is related with loading times.

I tried to creating animations in a setInterval. It's seems like solving the problem in a very bad way and makes everything chaotic.

 

Should I do try to make images redownloaded on every page render?

  • Like 1
Link to comment
Share on other sites

Definitely don't use setInterval(). And you only need to call ScrollTrigger.refresh() after the entire batch of images has finished loading (not each individual one). You're doing a lot of extra work there. 

 

This is more of a Next.js question than a GSAP one. You probably need to figure out what lifecycle events/callbacks are available and tap into the appropriate one that'd let you know when the layout is done being shifted around and the images have loaded completely. 

 

Good luck!

  • Like 3
Link to comment
Share on other sites

20 hours ago, Yunus Emre said:

I used it like 

<img onLoad={() => ScrollTrigger.refresh()} src="/images/1-1.jpg" />

 

And in the animation component I tried this;


element.onload = () => {
        ScrollTrigger.refresh();
      };

But it isn't working.

 

You can only have a single onload per element. Having onloads in your parallax code and JSX would count as two.

 

21 hours ago, Yunus Emre said:

Should I do try to make images redownloaded on every page render?

 

Images are cached, and if the images are already loaded then you don't need to worry about calling refresh.

 

12 hours ago, GreenSock said:

By the way, this issue report indicates onLoad isn't supported in Next.js: 

https://github.com/vercel/next.js/issues/20368

 

But maybe you need this: https://nextjs.org/docs/api-reference/next/image#onloadingcomplete

 

That's for the Image component in next.js, which Yunus isn't using.

 

  • Like 3
Link to comment
Share on other sites

Thanks for all good points. I learn a lot from them.

 

10 hours ago, OSUblake said:

That's for the Image component in next.js, which Yunus isn't using.

I think it's time to use it :D. Otherwise predetermined image sizes way to go. 

 

Just realized how much I say "Thanks" word. It's annoying but you people really helpful that I can't stop myself from thanking :D 

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