Jump to content
Search Community

Playing timeline on each element as it appears in the viewport using ScrollTrigger

JonQuayle test
Moderator Tag

Go to solution Solved by mvaneijgen,

Recommended Posts

Hi, I am trying to animate elements as the parent appears in the viewport. I have followed this article (https://ihatetomatoes.net/react-and-greensock-tutorial-for-beginners/#6-how-to-use-scrolltrigger-with-react) to animate the parent as it appears in the viewport using ScrollTrigger, but I have an image and text elements as children to each of these parents which I also want to animate in - but not as the individual elements appear in the viewport, when the parent appears in the viewport. I'm assuming the best thing to do would be to play a timeline for each(?), but am struggling with where that timeline would sit and how to reference the separate elements in the timeline. I'm building this in React so I don't know if I am supposed to be calling the elements in a certain way? Whatever I have tried so far hasn't worked so I've pulled it back to the point of the above link.

 

I'm also really struggling getting this into a Codepen as its React and is pulling data in from a headless CMS - it just isn't playing ball.

 

So the code below is animating in the parents elements correctly, but how can I set the ScrollTrigger on these parents elements, but animate their children rather than the element that is being watched by ScrollTrigger?

 

I'm sorry if this is a long post, I'm reaching the end of my understanding with this 😂

 

// Referencing the Featured Projects to reveal
  const revealRefs = useRef([]);
  // for each of the projects to reveal, add them to an array.
  // This will allow this array to be looped over and animate its children invididually
  revealRefs.current = [];

  const el = useRef();
  const q = gsap.utils.selector(el);

  useLayoutEffect(() => {
    revealRefs.current.forEach((el, index) => {

      gsap.fromTo(el, {
        opacity: 0,
      }, {
        ease: "sine.easeOut",
        duration: 0.8,
        opacity: 1,
        scrollTrigger: {
          markers: true,
          trigger: el,
          start: "top 85%",
        }
      });

    });
  }, []);

  // Adds all found refs to the revealRefs array for animation
  const addToRefs = (el) => {
    // Check if the element exists.
    // If it does not include it in the revealRefs array
    if(el && !revealRefs.current.includes(el)){
      revealRefs.current.push(el);
    }
  };

 

The actual markup is like this:

{projects.results.map((document) => (
      <div className="featured-project_wrapper" key={document.id} ref={addToRefs}>
        <PrismicLink
          className="featured-project_item"
          document={document}
          >
          <figure className="featured-project_image">
            <div className="reveal-overlay" style={{backgroundColor: document.data.main_colour}}></div>
            <PrismicNextImage
              field={document.data.featuredImage}
              imgixParams={{ q: 80 }}
              layout="fill"
            />
          </figure>
          <div className="featured-project_info">
            <h2 className="heading">
              <PrismicText field={document.data.projectTitle} />
            </h2>
            <div className="underlined-text-link">View project</div>
          </div>
        </PrismicLink>
      </div>
    ))}

 

Thanks

See the Pen ExEJaBK by JonQuayle (@JonQuayle) on CodePen

Edited by JonQuayle
Adding link to codepen
Link to comment
Share on other sites

Hey @JonQuayle could you try creating a demo in CodeSandbox, bellow there are examples for each of the major frameworks, including React.

 

Quote

If you're using something like React/Next/Nuxt/Gatsby or some other framework, you may find CodeSandbox easier to use. 

 

I personally like to create timelines for each of my ScrollTriggers so that scroll logic is separate from the tweens. Even if it is only one tween (it is never one tween, because ScrollTrigger is so fun you'll always add more tweens later)

 

let tl = gsap.timeline({
    // yes, we can add it to an entire timeline!
    scrollTrigger: {
      trigger: ".container",
      pin: true,   // pin the trigger element while active
      start: "top top", // when the top of the trigger hits the top of the viewport
      end: "+=500", // end after scrolling 500px beyond the start
      scrub: 1, // smooth scrubbing, takes 1 second to "catch up" to the scrollbar
      snap: {
        snapTo: "labels", // snap to the closest label in the timeline
        duration: {min: 0.2, max: 3}, // the snap animation should be at least 0.2 seconds, but no more than 3 seconds (determined by velocity)
        delay: 0.2, // wait 0.2 seconds from the last scroll event before doing the snapping
        ease: "power1.inOut" // the ease of the snap animation ("power3" by default)
      }
    }
  });

// add animations and labels to the timeline
tl.addLabel("start")
  .from(".box p", {scale: 0.3, rotation:45, autoAlpha: 0})
  .addLabel("color")
  .from(".box", {backgroundColor: "#28a92b"})
  .addLabel("spin")
  .to(".box", {rotation: 360})
  .addLabel("end");

See the docs for more examples

  • Like 2
Link to comment
Share on other sites

1 hour ago, JonQuayle said:

I'm also really struggling getting this into a Codepen as its React and is pulling data in from a headless CMS - it just isn't playing ball.

Also - just use vanilla JS and some coloured boxes to start with! Get the GSAP/animation bit right. Then when you're happy pull it in to react and worry about data wrangling.

Don't make life more difficult for yourself!

  • Like 1
Link to comment
Share on other sites

Thanks all, I've taken the time to recreate this in a codepen as simply as I can.

 

So, I've got the 'featured project' opacity animating in using scroll trigger fine, but I don't know where to start in animating children elements in when the parent container comes into view. I'm wanting the blue overlay to scale up to 0, revealing the image beneath, and fade the title and link element in from 0.

 

I'm probably making this harder with the project being in React.

 

Link to comment
Share on other sites

  • Solution

Thanks for the demo, this really helps! 

 

As I said, I would create a timeline and add these animations to the timeline. Then add ScrollTrigger to the timeline to have it function on scroll.

 

The best thing to do with ScrollTrigger is to remove it! This seems counter intuitive, but ScrollTrigger is just animating something on scroll, so just focus on the animation at first and only when you're happy with the animation add ScrollTrigger back in. 

 

I've animated the overlay and the title, I'll leave it up to you do add the link animation to the timeline. Start playing around with the position parameter to tweak the timing or have elements even animated in at the same time!

 

See the Pen bGvJVep?editors=0010 by mvaneijgen (@mvaneijgen) on CodePen

 

Good luck! Oh and try enabling the scrub: 1 code that is commented out and see what that does!

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