Jump to content
GreenSock

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

ScrollTrigger Usage with Gatsby and Smooth Scrollbar

Go to solution Solved by velkas,

Recommended Posts

I am using Gatsby JS and initializing smooth-scrollbar within a layout component and I've also configured the scroller proxy. Within a child component, I'm trying to setup an animation using scroll trigger but I'm not sure how to configure this. Also, the config does work after HMR fires but not after page refresh. I removed most of the markup from the page as I know the animation works - I think the issue is with syncing the scrollers.

 

layout.js:

import React, { useRef, useEffect } from "react"
import Navbar from "./navbar"
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import Scrollbar from 'smooth-scrollbar'
// import "../styles/locomotive-scroll.css"


const Layout = ({ children, location }) => {
  
  const scrollerRef = useRef()

  useEffect(() => {
    
    gsap.registerPlugin(ScrollTrigger)
    
    const scroller = scrollerRef.current

    const bodyScrollBar = Scrollbar.init(scrollerRef.current, { damping: 0.1, delegateTo: document, alwaysShowTracks: true })

    window.bodyScrollBar = bodyScrollBar

    ScrollTrigger.scrollerProxy(scrollerRef.current, {
      scrollTop(value) {
        if (arguments.length) {
          bodyScrollBar.scrollTop = value
        }
        return bodyScrollBar.scrollTop
      }
    })

    window.scroller = scrollerRef.current

    bodyScrollBar.addListener(ScrollTrigger.update)

    ScrollTrigger.defaults({ scroller: scroller })

    // ScrollTrigger.refresh()
    
    return () => {
      if (bodyScrollBar) bodyScrollBar.destroy()
      bodyScrollBar.removeListener(ScrollTrigger.update)
    }
  }, [location])
  
  return (
    <div className="global-wrapper scroller h-screen overflow-hidden" ref={scrollerRef}>

      <header className="global-header animate__animated animate__fadeIn">
        <Navbar />
      </header>


      <main>{children}</main>
      <footer>
        {/* © {new Date().getFullYear()}, Built with */}
        {` `}
        {/* <a href="https://www.gatsbyjs.com">Gatsby</a> */}
      </footer>
      
    </div>
  )
}

export default Layout

index.js:

import React, { useEffect, useRef } from "react"
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";


function Index() {

  const outroRef = useRef()
  const outroContentRef = useRef()

  useEffect(() => {

    gsap.registerPlugin(ScrollTrigger)

    gsap.fromTo(outroContentRef.current, {
      yPercent: "-50"
    }, {
      yPercent: "0",
      scrollTrigger: {
        scroller: window.scroller,
        trigger: outroRef.current,
        end: "bottom bottom",
        scrub: true,
        markers: true
      }, ease: "none"
    })

  }, []);

    return (
      <>
        {/* Page content */}
      </>
    )
}

export default Index

 

Link to comment
Share on other sites

Hi,

 

Have you tried this without the scroller proxy and just ScrollTrigger?

 

Can you provide a minimal live sample in Codesandbox, so we can take a better look at this?

 

Finally I'm not all that familiar with Gatsby (honestly if forced to work with a React site generator I prefer NextJS) and I could be wrong, but isn't the layout component the one that wraps virtually every page/route? Isn't a way to pass the references as props instead of attaching them to the window object? Considering that you can create SSR stuff with Gatsby that could throw an error during the build process since there is no window object in that particular phase.

 

Happy Tweening!!!

  • Like 2
Link to comment
Share on other sites

  • Solution

After some fiddling, the solution I came up with was to conditionally render the children. The scroll requires a ref to the scroll container so the init function is placed inside useEffect to guarantee the ref is defined. And because this component is at the "top level" we don't need to pass location to the useEffect callback. This seems to work but any improvements or suggestions are welcome 🤷‍♂️

 

import React, { useRef, useEffect, useState } from "react"
import Navbar from "./navbar"
import Scroll from './scroll'
import '../styles/smooth-scrollbar.css'


const Layout = ({ children }) => {
  
  let scrollerRef = useRef()
  let [scrollDefined, setScrollDefined] = useState(false)

  const initScroll = () => {
    Scroll(scrollerRef)
    setScrollDefined(true)
  }

  useEffect(() => {
    initScroll()
  }, [])
  
  return (
    <div className="global-wrapper scroller h-screen overflow-hidden" ref={scrollerRef}>

      <header className="global-header animate__animated animate__fadeIn">
        <Navbar />
      </header>
    
      <main>{ scrollDefined && children }</main>

      <footer>
        {/* © {new Date().getFullYear()}, Built with */}
        {` `}
        {/* <a href="https://www.gatsbyjs.com">Gatsby</a> */}
      </footer>
      
    </div>
  )
}

export default Layout

 

import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import Scrollbar from 'smooth-scrollbar'
import SoftScrollPlugin from './plugins/SoftScrollPlugin'

const Scroll = (scrollerRef) => { 
  
  const scroller = scrollerRef.current
  
  Scrollbar.use(SoftScrollPlugin)
  
  const bodyScrollBar = Scrollbar.init(scroller, { damping: 0.1, delegateTo: document, alwaysShowTracks: true })
  
  window.bodyScrollBar = bodyScrollBar
  
  gsap.registerPlugin(ScrollTrigger)
  
  ScrollTrigger.defaults({ scroller: scroller })
  
  ScrollTrigger.scrollerProxy(scroller, {
    scrollTop(value) {
      if (arguments.length) {
        bodyScrollBar.scrollTop = value
      }
      return bodyScrollBar.scrollTop
    }
  })

  ScrollTrigger.refresh()
  bodyScrollBar.addListener(ScrollTrigger.update)
}

export default Scroll

 

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