Jump to content
Search Community

Multiple ScrollTrigger animations in React

hantastic test
Moderator Tag

Go to solution Solved by Rodrigo,

Recommended Posts

Hi,

I'm trying to recreate the text animation on scroll from here: https://www.designbridge.com/about

There are full height sections with the text being position:fixed. It looks like the sections as they scroll in and out of view manage the opacity.

 

My attempt can be found here: https://codesandbox.io/s/uv9bws?file=/src/components/Home/Hero.tsx

 

/* eslint-disable array-callback-return */
import { gsap } from 'gsap/dist/gsap';
import { ScrollTrigger } from 'gsap/dist/ScrollTrigger';
import { useLayoutEffect, useRef } from 'react';
import styled from 'styled-components';

gsap.registerPlugin(ScrollTrigger);

const slides = [
  {
    id: 1,
    message: 'text line one',
  },
  {
    id: 2,
    message: 'text line two',
  },
];

const StyledHero = styled.section`
  background-color: var(--primary-colour);
  color: var(--primary-white);
`;

const StyledSlide = styled.div`
  background-color: var(--primary-colour);
  color: var(--primary-white);
  height: 100vh;
`;

const StyledInner = styled.div`
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 100%;
  text-align: center;

  .box1 {
    opacity: 0;
  }
`;

export const Hero = () => {
  const revealsRef = useRef([]);
  revealsRef.current = [];

  useLayoutEffect(() => {
    revealsRef?.current.map((el, index) => {
      const ctx = gsap.context(() => {
        gsap.to('.box1', {
          scrollTrigger: {
            id: `section-${index}`,
            trigger: el,
            end: 'bottom top',
            scrub: true,
            start: 'top top',
            markers: true,
          },
          opacity: 1,
          y: -10,
        });
      }, el);

      return () => {
        ctx.revert();
      };
    });
  }, []);

  const addToRefs = (el) => {
    if (el && !revealsRef.current.includes(el)) {
      revealsRef.current.push(el);
    }
  };

  return (
    <StyledHero>
      {slides.map((slide) => {
        return (
          <StyledSlide key={slide.id} ref={addToRefs}>
            <StyledInner>
              <h1 className="box1">{slide.message}</h1>
            </StyledInner>
          </StyledSlide>
        );
      })}
    </StyledHero>
  );
};

All the text fades in at the same time and I can't quite see what's going wrong. Any advice gratefully received!

 

 

Link to comment
Share on other sites

Hi @hantastic. I don't have time to build it out for you, but here are some tips: 

  1. Just focus on the text animation sequence and forget about linking it up to the scroll position at first. Build it in a single timeline. It should be pretty simple using the stagger property and/or the position parameter. Make it look the way you want (just playing straight through). Then, once you've got that done, hook it up to the scroll position with ScrollTrigger. 
  2. You're nesting things oddly in your useEffect() - just use ONE gsap.context() and put your loop inside of that so there's a single cleanup revert(): 
    // BAD
    useEffect(() => {
      array.forEach(el => {
        let ctx = gsap.context(() => {...}, el);
        return () => ctx.revert();
      });
    }, []);
    
      
    // GOOD
    useEffect(() => {
      let ctx = gsap.context(() => {
        array.forEach(el => {...});
      }, component);
      return () => ctx.revert();
    }, []);

    The way you're doing it would never run a cleanup function at all and you're creating a bunch of extra contexts. The extra contexts aren't terrible, just wasteful. 

I hope that helps.

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