Jump to content
Search Community

Scrolltrigger animation is laggy when page height varies

Byron Shi test
Moderator Tag

Go to solution Solved by Byron Shi,

Recommended Posts

Hi there, I'm building a section that shows timelines of multiple industries. When one is clicked, it expands and shows the detail.

To make the timeline stages look clearer, I applied a scrolltrigger animation to the stage element to pin it at the bottom of viewport.

When I scroll up or down, it looks pretty smooth. But when i expand or fold a industry row, the stage element becomes less responsive(drop down to around 2-3 fps, esspecially when folding).

What can i do to make the fixed part not laggy in this case?

 

See the Pen LYMOqgQ by byronshi (@byronshi) on CodePen

Link to comment
Share on other sites

Hi @Byron Shi,

 

You should never apply CSS transitions to anything that JavaScript is animating because not only is it horrible for performance, but it'll prolong all the effects because whenever JavaScript updates a value (which GSAP typically does 60 times per second), the CSS transitions interrupt and say "NOPE! I won't allow that value to be changed right now...instead, I'm gonna slowly make it change over time". So it disrupts things, adds a bunch of load to the CPU because you've now got CSS and JS both fighting over the same properties, but let's say you've got a 1-second tween and the CSS transitions are set to take 1000ms...that means what you intended to take 1 second will actually take 2 seconds to complete.

 

If I take a look at your CSS I see a lot of transitions and they don't seem to be scoped, which in my opinion is a definite nope! Personally If I apply a transition with CSS I do it as follows which only targets the opacity and background-color, nothing else, and them I take a mental note that I should not animate these properties with GSAP other wise it becomes laggy. 

 

transition: opacity, background-color;
transition-duration: 300ms;
transition-timing-function: ease;

 

Here I've removed all your transitions and it stops being 'laggy'. My advice update all your CSS transitions to be scoped and only target the things you don't animate with GSAP or even better remove your transitions all together and do every thing with GSAP! Hope it helps and happy tweening! 

 

See the Pen XWozGaE?editors=0100 by mvaneijgen (@mvaneijgen) on CodePen

  • Like 1
Link to comment
Share on other sites

4 minutes ago, mvaneijgen said:

Hi @Byron Shi,

 

You should never apply CSS transitions to anything that JavaScript is animating because not only is it horrible for performance, but it'll prolong all the effects because whenever JavaScript updates a value (which GSAP typically does 60 times per second), the CSS transitions interrupt and say "NOPE! I won't allow that value to be changed right now...instead, I'm gonna slowly make it change over time". So it disrupts things, adds a bunch of load to the CPU because you've now got CSS and JS both fighting over the same properties, but let's say you've got a 1-second tween and the CSS transitions are set to take 1000ms...that means what you intended to take 1 second will actually take 2 seconds to complete.

 

If I take a look at your CSS I see a lot of transitions and they don't seem to be scoped, which in my opinion is a definite nope! Personally If I apply a transition with CSS I do it as follows which only targets the opacity and background-color, nothing else, and them I take a mental note that I should not animate these properties with GSAP other wise it becomes laggy. 

 

transition: opacity, background-color;
transition-duration: 300ms;
transition-timing-function: ease;

 

Here I've removed all your transitions and it stops being 'laggy'. My advice update all your CSS transitions to be scoped and only target the things you don't animate with GSAP or even better remove your transitions all together and do every thing with GSAP! Hope it helps and happy tweening! 

 

 

 

 

Thanks for the remind, but after closely going through your reply, I'm afraid that's not key to the problem here. I'm aware of the css transition and js animation confliction. If you look into my code, you will see that all elements with css transition are not animated by js code. They only reacts to the class change of their parent, which I believe, does not cause performance or delay issue here.

 

In case I'm not explaining my "laggy" clear enough here, I took a video of it. Please take a look(the "1st, 2nd, 3rd industrial revolution" part).

There's only 1 or 2 frames placed between each animation, that's what it troubles me.

 

Link to comment
Share on other sites

Hi,

 

I agree with @mvaneijgen in the fact that the problem could reside somewhere else and not in something GSAP is doing. Here is a super simple example that toggles the height of an element, while another one is pinned:

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

 

As you can see there is no such issue there. The problem I can see in your setup is that you are actually animating the height of the container that definitely affects the start and end points of the ScrollTrigger instance that pins the element to the bottom of the screen. Now the conflict arises when ScrollTrigger has to refresh, even a single instance on every update of the height animation:

gsap.to($indInfo, {
  height: height,
  duration: .8,
  autoRound: false,
  ease: "expo",
  onUpdate() {
    //console.log(panoBottomFix)
    //panoBottomFix.update();
    window.panoBottomFix && panoBottomFix.scrollTrigger.refresh();
  }
});

The refresh method will take some time to execute and apply the changes and that will create those jumps or jitter you mention. Keep in mind that the onUpdate method is called on every GSAP tick (roughly every 16 milliseconds) and is quite probable that the ScrollTrigger refresh method (again, even if is called on a single instance) takes longer than that.

 

I would definitely recommend either use a shorter height animation and maybe debounce the update callback or switch to an onComplete callback. Another option could be to hide the element while the height animation is happening using autoAlpha: 0 in the onStart callback, and show it again once the animation is completed and the ScrollTrigger instance has been refreshed and everything is back on it's expected position.

 

Hopefully this helps

Happy Tweening!

Link to comment
Share on other sites

  • 3 weeks later...
  • Solution
On 9/21/2023 at 12:33 AM, Rodrigo said:

Hi,

 

I agree with @mvaneijgen in the fact that the problem could reside somewhere else and not in something GSAP is doing. Here is a super simple example that toggles the height of an element, while another one is pinned:

 

 

 

As you can see there is no such issue there. The problem I can see in your setup is that you are actually animating the height of the container that definitely affects the start and end points of the ScrollTrigger instance that pins the element to the bottom of the screen. Now the conflict arises when ScrollTrigger has to refresh, even a single instance on every update of the height animation:

gsap.to($indInfo, {
  height: height,
  duration: .8,
  autoRound: false,
  ease: "expo",
  onUpdate() {
    //console.log(panoBottomFix)
    //panoBottomFix.update();
    window.panoBottomFix && panoBottomFix.scrollTrigger.refresh();
  }
});

The refresh method will take some time to execute and apply the changes and that will create those jumps or jitter you mention. Keep in mind that the onUpdate method is called on every GSAP tick (roughly every 16 milliseconds) and is quite probable that the ScrollTrigger refresh method (again, even if is called on a single instance) takes longer than that.

 

I would definitely recommend either use a shorter height animation and maybe debounce the update callback or switch to an onComplete callback. Another option could be to hide the element while the height animation is happening using autoAlpha: 0 in the onStart callback, and show it again once the animation is completed and the ScrollTrigger instance has been refreshed and everything is back on it's expected position.

 

Hopefully this helps

Happy Tweening!

Sorry for the late reply, I was on vacation last couple of days.

 

I changed the way I fixed the elements to the same as possible in the demo, using "ScrollTrigger. create" instead of "gsap. to", and now it looks like there's no problem.

I'm confused then, why a refresh invokation to a ScrollTrigger instance nested inside "gsap.to" takes longer than one that's  created directly by "ScrollTrigger. create"?

 

  • Like 1
Link to comment
Share on other sites

Hi,

 

Most likely because the refresh method associated with a particular GSAP instance (Tween/Timeline) has to do other operations besides the ones attached to the ScrollTrigger instance, especially if you had invalidateOnRefresh: true on your setup.

 

Is great that you were able to figure it out and thanks for sharing your solution with the community!

 

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