Jump to content
Search Community

GSAP ScrollTrigger markers are set before animation that reveal the content

Dronius test
Moderator Tag

Recommended Posts

In my react application I am using two scroll triggers, one for the main "reveal" animation and another for "another" animation. The problem is that when the scrollTrigger markers are set for the "another" animation the "reveal" animation hasn't happened yet and that causes an offset in the "another" animation markers. Here is what I am talking about:

image.thumb.png.7ae6d0b22917d76c74a170b67114a58c.png

 

The start and end markers should be where the red line is, but instead they are offset by 70px. This is because when the page loads the "reveal" animation that moves the whole element up 70px hasn't ran and it only runs when the element has come into view. Here is the code:

 

The reveal animation that is offseting the element(translateY):

  useLayoutEffect(() => {
    if (elementToAnimate) {
      const context = gsap.context(() => {
        gsap.from(elementToAnimate, {
          duration: 0.55,
          translateY: 70,
          opacity: 0,
          ease: 'power.out',
          scrollTrigger: {
            trigger: elementToAnimate,
            toggleActions: toogleActions
              ? toogleActions
              : 'restart reverse restart reverse',
            start: 'top 90%',
            end: 'bottom 10%',
          },
        });
      });

      return () => context.revert();
    }
  }, [elementToAnimate]);

 

The "another" animation(the important part of the code below is that it sets it's markers by the horizontalBorderToAnimate which is initialy offset by 70px since the "reveal" animation hasn't ran yet):

  useLayoutEffect(() => {
    const horizontalBorderToAnimate = horizontalBorderBottomRef.current;
    const verticalBorderToAnimate = verticalBorderRightRef.current;

    if (horizontalBorderToAnimate && verticalBorderToAnimate) {
      const customToggleActions = 'restart reverse restart reverse';
      const context = gsap.context(() => {
        gsap.from(horizontalBorderToAnimate, {
          duration: 0.55,
          ease: 'power.out',
          width: '100%',
          scrollTrigger: {
            markers: true,
            trigger: horizontalBorderToAnimate,
            toggleActions: customToggleActions,
          },
        });

        gsap.from(verticalBorderToAnimate, {
          duration: 0.55,
          ease: 'power.out',
          height: '100%',
          scrollTrigger: {
            trigger: horizontalBorderToAnimate,
            toggleActions: customToggleActions,
          },
        });
      });
      return () => context.revert();
    }
  }, []);

How should I fix this?

Link to comment
Share on other sites

It's pretty tough to troubleshoot without a minimal demo - the issue could be caused by CSS, markup, a third party library, your browser, an external script that's totally unrelated to GSAP, etc. Would you please provide a very simple CodePen or Stackblitz that demonstrates the issue? 

 

Please don't include your whole project. Just some colored <div> elements and the GSAP code is best. See if you can recreate the issue with as few dependancies as possible. If not, incrementally add code bit by bit until it breaks. Usually people solve their own issues during this process! If not, then at least we have a reduced test case which greatly increases your chances of getting a relevant answer.

 

Here's a starter CodePen that loads all the plugins. Just click "fork" at the bottom right and make your minimal demo

See the Pen aYYOdN by GreenSock (@GreenSock) on CodePen

 

Using a framework/library like React, Vue, Next, etc.? 

CodePen isn't always ideal for these tools, so here are some Stackblitz starter templates that you can fork and import the gsap-trial NPM package for using any of the bonus plugins: 

 

Please share the StackBlitz link directly to the file in question (where you've put the GSAP code) so we don't need to hunt through all the files. 

 

Once we see an isolated demo, we'll do our best to jump in and help with your GSAP-specific questions. 

Link to comment
Share on other sites

Hey, so after some time trying I couldn't manage to replicate this bug on stackBlitz, although it is still there in my actual project. I don't know if this is much help, but here's the non buggy version of my project - https://stackblitz.com/edit/react-apvecf?file=src%2Findex.js 

The problem is the same one that I mentioned in my initial post, maybe someone has any ideas what could be causing this, maybe something I forgot to add to stackblitz?

Here is the still active bug in my actual project:

image.thumb.png.247c75a6d9c73c324492104a6525410d.png

 

Link to comment
Share on other sites

Hey,

 

it's pretty tough as a reader to figure out what's causing the layout shifts (especially if it is not reproducible). My best guess would be that the font loading finished after the ScrollTrigger instance was created.

But it could also be caused by

  • another 3rd party library/script,
  • lazy loading of images, components, etc.
  • your own code.

So you'll have to dig a little deeper to find out what's causing it. After you find it, call ScrollTrigger.refresh() to recalculate the start and end values (ScrollTrigger Doc.).

 

If my guess is correct, you can read this article, which explains the problem better than I ever could, and provides strategies for solving it. 

 

But to summarize a bit:

  • use could use font-display 
  • find a system font that is similar to your current one,
  • host the font yourself, (in case you are using nextjs: Font Optimization)
  • etc.

If you need more information, search for "layout shifts"/"hosting web fonts"/"etc" and you will find a lot of material to go through. You can also search for it in this forum. I'm sure there are other people who had a similar problem as you.

 

Also, you might want to use a timeline if you are using the same trigger element in your ScrollTriggers. Just make sure that you start the animations in the timeline at the same time (positioning parameters). Advanced Animation Techniques

 

Hope this helps and good luck with your project.

Link to comment
Share on other sites

@alig01 Thank you for the reply. I linked the layout shift to the reveal gsap animation because of a few reasons:

  1. In my custom useFadeIn() hook(demo) i use the translateY: 70, property in my animation, which basically determines exactly how much my markers shift, for example if I change it to translateY: 10, they move only 10px down.
  2. For me it makes sense because I am using .from() so the content of the page is set 70px down (because of translateY: 70) initially and that's when the scrollTrigger markers for another animation are set. The content only moves 70px up when the content comes into view, but then the other animation has already set it's markers 70px down and that is what causes the "layout shift". 

I thought I am missing some key point, because it seems like a common scenario "animation offsetting another animation scrollTrigger".

Link to comment
Share on other sites

Hi,

 

The issue is pretty obvious actually. You are using a from() instance that moves the element on the Y axis and at the same time you are creating a different set of ScrollTrigger instances that are triggered by DOM elements inside the first ScrollTrigger instance. In order to clarify  you are creating a from() instance in your hook, that is triggered and animates the aboutRef.current element. That particular ref is the DOM element that is the parent of every other element in your DOM tree structure:

<div id="about-div" ref={aboutRef}>
  <div id="about-div-photo">
    <div className="about-top-div" />
    <div className="about-middle-div" id="about-image-div"></div>
    <div className="about-bottom-div" />
  </div>
  <div id="about-div-text">
    <div
         className="about-vertical-border"
         id="about-vertical-border-left"
         />
    <div className="about-top-div">
      <div id="about-image-top-div"></div>
    </div>
    <div className="about-middle-div">
      <div id="about-middle-div-left-side">
        <div id="about-page-big-text-div">Something</div>
        <div id="about-page-smaller-text-div">
          In publishing and graphic design, Lorem ipsum is a placeholder
          text commonly used to demonstrate the visual form of a document
          or a typeface without relying on meaningful content. Lorem ipsum
          may be used as a placeholder before final copy is available.
        </div>
      </div>
    </div>
  </div>
  <div id="about-div-end">
    <div
         className="about-vertical-border"
         id="about-vertical-border-right"
         ref={verticalBorderRightRef}
         />
    <div className="about-top-div" />
    <div className="about-middle-div" />
  </div>
  <div
       id="about-horizontal-border-top"
       className="about-horizontal-border"
       />
  <div
       id="about-horizontal-border-bottom"
       className="about-horizontal-border"
       ref={horizontalBorderBottomRef}
       />
</div>

Then you create ScrollTrigger instances for the horizontalBorderBottomRef and verticalBorderRightRef, those reside inside the previous element. On top of that the instance you create in your hook is a from instance so that takes the element from it's natural position to the position you pass to the GSAP config, since you are animating on the Y axis 70 pixels, that's the offset you get. If you change that, the offset changes as well.

 

Also you are making one of the biggest mistakes when it comes to ScrollTrigger that is animating the trigger element, especially in the Y axis (you are doing that in all your ScrollTrigger instances actually). Is always better to not do that in order to avoid this type of issues.

 

Finally I think your setup is a bit convoluted IMHO, especially in the way you are creating your animations, if you want to reduce the amount of code you are using or want to use the same type of animation over and over, you can register a particular effect in order to reuse it:

https://greensock.com/docs/v3/GSAP/gsap.registerEffect()

 

Hopefully this helps.

Happy Tweening!

  • Like 1
Link to comment
Share on other sites

Is quite simple in theory: Don't animate the triggers and don't animate the parent on the Y axis, especially if you want to create ScrollTrigger-based animations for child nodes of that particular element.

 

Another alternative could be to create a single timeline for all the animations and give that particular timeline the ScrollTrigger configuration.

 

This falls more in the consulting side of things than support on a free forum. Unfortunately we don't have the time resources to create custom solutions for our users, or solve issues on how structure React (or any other framework) apps.

 

You can hire us on a consulting basis or post in the Jobs & Freelance forums to get help there.

 

Good luck with your project!

Happy Tweening!

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