Jump to content
Search Community

GSAP in GatsbyJS scrolls twice after coming back to the website page

strawberry19 test
Moderator Tag

Go to solution Solved by OSUblake,

Recommended Posts

I've noticed some strange behavior of scrolling in GatsbyJS. I have a container with full-page sections that are scrolled with GSAP.

import React, { useEffect } from "react"
import scroll from "../assets/javascript/scroll"

export default function IndexPage() {
  useEffect(() => {
    scroll()
  }, [])

  return (
    <div className={styles.container}>
      <Header />
      <Products />
      <Contact />
      <Footer />
    </div>
  )
}

Everything works fine... until I go to another tab of a browser and come back to my website again. After doing that GSAP 'breaks' and scrolls two full-page sections one after another. Even if I scroll a mouse wheel a bit. And sometimes GSAP can't scroll the section at all. It looks like a full-page starts moving but suddenly the scrolling stops and GSAP places the current section to it's place.

I don't know  how Gatsby works under the hood but maybe the scrolling script loads and runs again after coming back to the page? But I run the script in useEffect

 

import { gsap } from "gsap"
import { ScrollTrigger, ScrollToPlugin } from "gsap/all"

export default function () {
  console.log("i am here!!!")

  gsap.registerPlugin(ScrollTrigger)
  gsap.registerPlugin(ScrollToPlugin)

  const sections = document.querySelectorAll("section")

  // this scrolling object just allows us to conveniently call scrolling.enable(), scrolling.disable(), and check if scrolling.enabled is true.
  // some browsers (like iOS Safari) handle scrolling on a separate thread and can cause things to get out of sync (jitter/jumpy), so when we're animating the scroll position, force an update of GSAP tweens when there's a scroll event in order to maintain synchronization)
  const scrolling = {
    enabled: true,
    events: "scroll,wheel,touchmove,pointermove".split(","),
    prevent: e => e.preventDefault(),
    disable() {
      if (scrolling.enabled) {
        scrolling.enabled = false
        window.addEventListener("scroll", gsap.ticker.tick, { passive: true })
        scrolling.events.forEach((e, i) =>
          (i ? document : window).addEventListener(e, scrolling.prevent, {
            passive: false,
          })
        )
      }
    },
    enable() {
      if (!scrolling.enabled) {
        scrolling.enabled = true
        window.removeEventListener("scroll", gsap.ticker.tick)
        scrolling.events.forEach((e, i) =>
          (i ? document : window).removeEventListener(e, scrolling.prevent)
        )
      }
    },
  }

  function goToSection(section, anim, i) {
    console.log(scrolling.enabled)

    if (scrolling.enabled) {
      // skip if a scroll tween is in progress
      scrolling.disable()

      gsap.to(window, {
        scrollTo: { y: section, autoKill: false },
        onComplete: scrolling.enable,
        duration: 1,
      })

      anim && anim.restart()
    }

    console.log(section)
  }

  sections.forEach((section, i) => {
    const intoAnim = gsap.from(section.querySelector(".right-col"), {
      yPercent: 50,
      duration: 1,
      paused: true,
    })

    ScrollTrigger.create({
      trigger: section,
      start: "top bottom-=1",
      end: "bottom top+=1",
      onEnter: () => goToSection(section, intoAnim),
      onEnterBack: () => goToSection(section),
    })
  })
}

 

 

Link to comment
Share on other sites

You're going to have to write that code so it works with React and you can kill stuff in the return function of your useEffect. Right now you have no access to that stuff because you isolated it inside a function.

 

useEffect(() => {

  // create stuff
  
  return () => {
    // kill stuff you created
  };  
}, [])

 

Link to comment
Share on other sites

@OSUblake I'm sorry for bothering you again but I edited my code. But it didn't fix the problem.

Actually I don't understand how killing the ScrollTrigger and other event listeners should fix the problem. I guess I gave you an unclear description of the problem so you misunderstood me.

Let me make it clear. I open a tab in a browser and go to my website. The scrolling works fine. Then I open a new tab and go to (let's say) google.com and spend some time on that website. The tab with my website is still open in a background. Then I switch from google tab back to my website tab. And now GSAP scrolling starts to glitch. I never go to any other website in that browser tab. Also I never go to another route of my website. I just open an index page. Switch to another browser tab and switch back. I have no idea how and why but exactly these actions cause the problems.

Code:

export default function IndexPage() {
  useEffect(() => {
    gsap.registerPlugin(ScrollTrigger)
    gsap.registerPlugin(ScrollToPlugin)

    const sections = document.querySelectorAll("section")

    const scrolling = {
      enabled: true,
      events: "scroll,wheel,touchmove,pointermove".split(","),
      prevent: e => e.preventDefault(),
      disable() {
        if (scrolling.enabled) {
          scrolling.enabled = false
          window.addEventListener("scroll", gsap.ticker.tick, { passive: true })
          scrolling.events.forEach((e, i) =>
            (i ? document : window).addEventListener(e, scrolling.prevent, {
              passive: false,
            })
          )
        }
      },
      enable() {
        if (!scrolling.enabled) {
          scrolling.enabled = true
          window.removeEventListener("scroll", gsap.ticker.tick)
          scrolling.events.forEach((e, i) =>
            (i ? document : window).removeEventListener(e, scrolling.prevent)
          )
        }
      },
    }

    function goToSection(section, anim, i) {
      console.log(scrolling.enabled)

      if (scrolling.enabled) {
        // skip if a scroll tween is in progress
        scrolling.disable()

        gsap.to(window, {
          scrollTo: { y: section, autoKill: false },
          onComplete: scrolling.enable,
          duration: 1,
        })

        anim && anim.restart()
      }

      console.log(section)
    }

    sections.forEach((section, i) => {
      const intoAnim = gsap.from(section.querySelector(".right-col"), {
        yPercent: 50,
        duration: 1,
        paused: true,
      })

      ScrollTrigger.create({
        trigger: section,
        start: "top bottom-=1",
        end: "bottom top+=1",
        onEnter: () => goToSection(section, intoAnim),
        onEnterBack: () => goToSection(section),
      })
    })

    return () => {
      ScrollTrigger.kill()
    }
  }, [])

  return (
    <div className={styles.container}>
      <Header />
      <Products />
      <Contact />
      <Footer />
    </div>
  )
}

 

Link to comment
Share on other sites

  • Solution

You wouldn't use ScrollTrigger.kill(). Assuming you want to kill every single trigger...

 

ScrollTrigger.getAll().forEach(t => t.kill())

 

And I also don't know what that scrolling object is doing. It looks like it's adding event listeners, so you will have to remove whatever that is doing.

 

Link to comment
Share on other sites

Thank you very much for fixing my code. But I figured out that the problem could be not in GSAP or my component. I guess the problem is with the layout. I'm not sure but resizing the browser window fixed the scroll problem. Must be something with the coordinates I guess... anyway thank you!!

Link to comment
Share on other sites

@OSUblake hello again. I spent 2 days trying to figure out what causes the problem. First I though it was the html-layout. But then I noticed that the scrolling glitches only in Google Chrome. Never in Mozilla Firefox. Not sure about Opera, still testing.

So let me explain the situation. Maybe it would help you fix the library (if needed).

I use GSAP to scroll full-page sections. With plain HTML/CSS/JS the GSAP scrolling always works fine in Chrome. But I use GSAP with GatsbyJS (which, in turn, uses React).

Then I create several React-components. Each component is just a full-page section element that has some simple html inside (spans, h1, paragrapghs or plain text). When I scroll those components it works fine in Chrome.

Then in those React-components I replace that simple html with some more complex JSX. Like creating elements with .map(). And that is what breaks the GSAP scrolling in Google Chrome. Once again, in Mozilla Firefox it still works prefect.

My Chrome version is 99.0.4844.82. GSAP version is 3.9.1.

Link to comment
Share on other sites

Creating elements with map is fine, I do it all time. ScrollTrigger does not run in React/Gatsby. It's a side effect, so as long as your DOM is correct, it should be fine. ScrollTrigger is used by thousands of React devs, and the only known issue is a from bug that will be fixed in the next version.

 

If you think there is a bug with ScrollTrigger, can you provide a minimal demo that clearly shows the issue? We of course want to make sure all bugs are fixed before the next release.

Link to comment
Share on other sites

@OSUblake I tried to make the demo as minimal as possible. Here it is: https://codesandbox.io/s/wizardly-brook-bhzkit?file=/src/components/style.module.css

Please, try it in Chrome. Open the link scroll the page a bit. Then switch to another browser tab and then switch back to the codesandbox. If it still works fine, then repeat these steps 5-6 times and you will probably see what I was talking about.

 

Please, let me know if you will have the same problem with scrolling as I do.

 

P.S. As you can see in the second.js file I tried to create simple elements with map() and it didn't broke the scrolling. But when I created GatsbyImages using .map() the scrolling started to glitch.

Link to comment
Share on other sites

I'm still not sure what the glitch you are referring to is. If you're using images, you probably have to do ScrollTrigger.refresh() after each one loads.

 

And I'm still trying to understand that scrolling object? Why do you have a gsap.ticker.tick call in there?

 

 

Link to comment
Share on other sites

20 minutes ago, OSUblake said:

Maybe the visibiliity change is messing with your animations. Try this.

 

If that doesn't work, can you make a simple Codepen without Gatsby/React? Just vanilla JS and HTML. It's very difficult to troubleshoot when there's a framework in the way.

 

Link to comment
Share on other sites

@OSUblake I tried and it didn't help. Maybe I do something wrong. Anyway I will post a Codepen example tomorrow.

But could you please tell me where to put that tickGSAPWhileHidden in my code? So we are both sure that the code is 100% correct. You also mentioned gsap.ticker.tick. What's wrong with that? How should I fix the code?

 

I'm sorry for taking so much of your time. But I just won't rest until I figure out what causes this glitch. Maybe I use GSAP incorrectly... but why does it work fine in any other browser except for Chrome then?

Two more examples. In the first example the animation stopped halfway between 2 blocks

https://imgur.com/a/QYaFQcd

In the second example I scrolled 1 time but it scrolled 2 blocks one after another.

https://imgur.com/a/gAjqtZK

Link to comment
Share on other sites

@OSUblake

Quote

can you make a simple Codepen without Gatsby/React? Just vanilla JS and HTML. It's very difficult to troubleshoot when there's a framework in the way.

As I said before it works perfect with vanilla JS/HTML.

 

UPD. I uninstalled all extensions in Chrome. Uninstalled and installed the Chrome itself again. Run the code in incognito mode. Nothing helped, still having the problem.

Also installed and tried Yandex browser which is build on top of Chromium. Same result...

 

I guess I should give up since no one can undertand the reason for that. Thanks for your help anyway :)

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...