Jump to content


Issue with nav reduce/expand animation on scroll

Recommended Posts

Hey there everyone! Hope you're doing great today : )


This is my first time posting here on the Forum. I'm a pretty new GSAP user and I wanna start by saying I absolutely love this tool!
Thank you so much to all the creators and the team that maintains and continues building this, it's just a truly awesome resource!

Now on to the issue I'm facing..
I have this nav animation that reduces/expands the nav depending on your scroll position. The idea is that the nav is always in its expanded state when the scroll position is at the very top, and always in its reduced state whenever you're anywhere else (i.e.: at any point further down the page).
Because my reduce animation is different than my expand (i.e.: one is not an exact "reverse" of the other), I can't just have one animation and reverse it based on the scroll position, hence why I have two timelines.


Everything works 90% of the time, but if you scroll to the top and back down (or the other way around) really fast, you get a weird "in between" state that is incorrect, and I really can't figure out why or how to correct it.



Here are a few quick screen grabs showing the issue and how to reproduce it

(currently happening if you scroll slowly, wait for the animation to play, then scroll the other way and wait for the other animation to play):

(currently happening if you scroll both directions [down up down, up down up, etc] pretty quickly, or if you load the page in a scroll position other than the very top - i.e.: you scroll down and then reload, etc):

After a ton of testing with different combinations of toggleActions, trying to have different scrollTriggers (one for each timeline), trying it with just one, etc, I was finally able to get it somewhat working with an "onEnterBack" callback, but still can't figure out why I'm getting this weird "in between" state shown in the video above.


What you see in the video and in codepen is the simplest version of the current site I could manage to recreate, removing all unnecessary code etc, hopefully it's easy enough to understand. I also went ahead and made the scrollTrigger trigger element visible (it's the small blue square in the upper left corner) in hopes of making it easier to see what's happening.

Any comments, suggestions, ideas, etc are truly appreciated!


If you made it this far, thank you very much for taking the time and I hope you can shed some light on this hehe


Thanks!! 🙏🙏

Fernando : )

See the Pen yLjjLMZ by fbe28 (@fbe28) on CodePen

Link to comment
Share on other sites

Hi @fbe28 and welcome to the GreenSock forums!


The reason for this is because you have two different timelines fighting for control over the same properties in the same elements, like the height of the ".nav-mask" element, just to mention one. Also IMO it's quite unnecessary to have two different GSAP instances to take the menu from state A to state B and then revert it back to state A. Just create a single timeline that controls everything and play/reverse based using ScrollTrigger's  toggleActions.


I would try something like this:

function navTimelines(moveTopNavLinksBy) {
  let expandNavTl = gsap.timeline({
    paused: true,
    defaults: { ease: Power1.easeInOut, duration: 0.35 }
    .to(".tb-logo-top-wrap", { height: "0em", duration: 0.2 })
    .to(".top-nav-link.bottom-10", { opacity: 0, duration: 0.2 }, "<0.2")
    .to(".top-nav-links", { y: moveTopNavLinksBy }, "<")
    .to(".nav", { backgroundColor: "rgba(255,255,255,0)", duration: 0.2 }, "<")
    .to(".nav", { color: "#000", duration: 0.2 }, "<")
    .to(".top-nav-links.top-left", { color: "#000", duration: 0.2 }, "<")
    .to(".menu-btn-line", { backgroundColor: "#000", duration: 0.2 }, "<")
      { height: "100%", duration: 0.8, ease: Power2.easeInOut },
    trigger: ".nav-trigger",
    markers: { startColor: "green", endColor: "red" },
    start: "top 10px",
    onLeave: () => expandNavTl.timeScale(1).play(),
    onEnterBack: () => expandNavTl.timeScale(1.5).reverse(),

I noticed you have shorter durations for some instances in the timeline for the enter back callback, so I used timeScale(1.5) to speed up the animation when it goes back:

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

Finally you have CSS transitions in some of your elements, mixing CSS transitions and GSAP will cause some issues 99% of the times and we don't recommend that, especially if both CSS and GSAP are animating the same property. Also using transition: all 600ms ease; is a recipe for troubles if, for some reason, something else changes that perhaps you don't want to animate.


Happy Tweening!

  • Like 1
Link to comment
Share on other sites

Hey there, Rodrigo! How are you today?

Thank you so much for the thorough response, I really appreciate it! : )

Everything you said makes sense, and I was in fact suspicious of this being an issue with the timelines "fighting" for control over the same elements/properties.

The only issue is that, as I had explained in my main thread, I need to have a slightly different timeline for the way back (i.e.: it's not the exact reverse of the other one) as per my design spec, so simply reversing it wouldn't work.

Is there maybe another way I could achieve that?


Thank you so much once again!


Link to comment
Share on other sites

Hey Fernando,


Sorry  for the delay, it's been a bit busy around here, but haven't forgotten about this.


Yeah, having two different instances battling for stuff is not ideal and most of the times leads to issues such as the one you're experiencing.


I made some changes in the original codepen to make it look smoother and give a better feeling while using a single timeline:

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


Let me know how this works out.


Happy Tweening!

Link to comment
Share on other sites

Hey there, Rodrigo! How are you?


No worries, thank you so much once again for the response : )

It's been quite busy over here as well, sorry for the delay.

On my current client project, I ended up implementing your suggested solution and it now seems to be working reliably so thank you for that!


I do still wonder, though, if there would be a way to control the way back from an animation like this independently (like another timeline, although now I know doing it with a timeline per se won't work properly).

In my opinion, this is the type of subtlety that can make something feel that much nicer and it's really something I would like to be able to achieve.

Especially with other "toggle" type use cases like an open/close animation for a menu, etc, where you may want elements to have a different choreography depending on what state you are animating to.

Sorry to insist on this, but do you have any other ideas of how I could achieve that individual control without using the normal reverse method?

Thanks again so so much!


Link to comment
Share on other sites

Hey Fernando,


I'll keep the thread in my backlog in order to see if there is some way to implement this the way you want, as it would be a good resource for many other users. Hopefully I'll be able to whip something ASAP and I'll keep you posted


Glad to hear that the solution kind-of worked ;) 


Happy Tweening!

Link to comment
Share on other sites

Hey there Rodrigo!

Amazing, I really appreciate that, super stoked to see how we could achieve this!


And, yes, the other solution and explanation definitely helped me a lot in the meantime! Especially with understanding why the issue was happening and what would be a more fool proof way of doing it.


Thank you very much!

Fernando : )

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.