Jump to content
Search Community

multiple timelines and reversing from specific labels

emjay test
Moderator Tag

Go to solution Solved by Rodrigo,

Recommended Posts

Hey and Hello :)


I have a small problem and have been trying different things for some time.

I can only solve the problem if I make the heading visible again in onReverseComplete with gsap.to, but this is not really the best solution. I am not satisfied with it. 

Okay, let me describe the problem and expected behaviour:


I click on button 1, then the headline disappears to the top and the content comes from the bottom. If I click on button 1 again, it goes backwards again. So far, so good.

We start again. If I click on button 1, the headline disappears and the content appears. If I then click Button 2, the content disappears to the top and the new content appears from the bottom. Everything is still fine. The headline should not be visible.

And no where the problem arises:

We start again. If I click on button 1, the headline disappears and the content appears. If I then click Button 2, the content disappears to the top and the new content appears from the bottom.
But if I now click on button 2 again, the content should disappear to the bottom again and the headline should reappear from the top.
So it's more or less the same as before. Headline visible. But that's exactly what doesn't work. The headline remains hidden.


Don't be surprised about the HTML structure, the element works mobile like an accordion.

I hope someone can show me where I made the mistake. :)


See the Pen 2acd0ead5d66b2f1081ff3e168d533af by emjay (@emjay) on CodePen

Link to comment
Share on other sites

  • Solution



You can use a fromTo instance for the headline:

  .set(dl, { autoAlpha: 1 })
  .fromTo(headline, {  autoAlpha: 1, y: 0  }, { autoAlpha: 0, y: -100 })
  .from(dt, { autoAlpha: 0, y: 100 }, "<.1")
  .from(dd, { autoAlpha: 0, y: 100 }, "<.2")
  .to(dt, { immediateRender: false, autoAlpha: 0, y: -100 })
  .to(dd, { immediateRender: false, autoAlpha: 0, y: -100 }, "<.1");

That makes it work in the way you intend and are describing in the two steps to reproduce the issue:

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


Hopefully this helps.

Happy Tweening!

  • Like 1
Link to comment
Share on other sites

Hello @Rodrigo,

Thank you for your solution, at first glance it looked great, but then I found another problem.

Please click the buttons in the following order:
1 - 2 - 2 - 1 (the heading does not disappear)
1 - 2 - 1 - 1 - 2 (the text does not appear)


For the 1 - 2 - 2 - 1 example, at the first click on button 1, dlTimeline.reversed() is true. The second click, after 2 - 2 dlTimeline.reversed() is false. I explicitly set dlTimeline.reversed(true) in the second else, but this won't help.

My possible solution is to create a timelines array in line 7: let timelines = [];
and push the timeline to this array after all timeline steps are created (line 43): timelines.push(dlTimeline);

Then I use onReverseComplete to reset all timelines:

onReverseComplete: function () {
	timelines.forEach(function(tl) {
		if (tl !== dlTimeline) {

Is this a good solution? Or could it be solved better?

See the Pen bff7eaf4c61a41261ee6f5ea12338810 by emjay (@emjay) on CodePen

Link to comment
Share on other sites



If it ain't broken don't fix it, right? ;)


This type of scenarios can be tricky as you already found out. In order to save some brain cells from dying because of countless head banging on the desk (not because you're listening to metal music, those are the good head bangs), I explore two possible routes.


One is to create the animations on the fly when the button is clicked, not create them ahead.


Two, instead of adding the headline animation to every timeline, create a single animation. Play/reverse that animation and play the animation for the specific button using an index value and the onComplete callback of the  heading animation. Then when reversing the animation of a specific button use the onReverseComplete callback to either reverse the heading animation or play the animation of the target button.


As I mentioned those are just ideas based on my experience, but every scenario posts it's own particular challenges, so if your current solution works and doesn't create any problem, then stick with it.


Happy Tweening!

  • Like 1
  • Haha 1
Link to comment
Share on other sites

Hi @Rodrigo,

Thank you for this encouraging post. It was indeed already like that. :) Last but not least, could you help me with one more thing?
I don't understand why the delay doesn't work. At one point I do the following:


setTimeout(function() {
}, 400);

However, I only do this because the delay doesn't work, I would much rather use this:


Why do I need a delay at this point? Because otherwise one text animates over the other. setTimeout helps to avoid this, but with the following code I prevent the user from double-triggering a timeline by clicking quickly. Of course, the .isActive() doesn't work in the 400ms when setTimeout is active. Thats why i would prefer .delay() Do you know what I mean?

if (lastTimeline && lastTimeline.isActive()) return;
if (dlTimeline.isActive()) return;

I think @akapowl had the same problem here, but in my case I think its different.

Thank you very much for your time, you are really very helpful.


Link to comment
Share on other sites

1 hour ago, emjay said:

I think @akapowl had the same problem here, but in my case I think its different.


I'd say: No and Yes.

While my problem was similar, it was also very different, because I never needed to play my timeline from a specific point other than the start.

The gist of that older thread you linked to is, that by making a shear mistake, in an older version I somehow got things to work as I intended them to work, although the methods I used for that apparently were never supposed to do what I intended it them to do in combination, in the first place.


As Jack said in that thread:


When someone calls play() on an animation, they typically expect it to...well...play :)

So the suggestions Carl made in that thread, would probably be a way to go for you to make it work like you intend.


either of these options will work

tween.delay(5).restart(true); //true means the delay will be honored when restart() is called
gsap.delayedCall(5, ()=> tween.play());

Now, in my case, technically both would have worked just fine; because as I mentioned, I only needed my timeline to play delayed from its start.

But in your case, since it looks to me like you want it to play from a label at some point into the timeline, that of course won't be an option, because .delay() only ever would set a delay at/from the start of a timeline (and not somwhere in between the tweens on that timeline) - this is from the docs:



Gets or sets the animation’s initial delay which is the length of time in seconds before the animation should begin. 




So the one option out of these to go with, for you would be to use a delayedCall - which is nothing but GSAP's own and very much refined version of a setTimeout() call and should always be preferred over a setTimeout when working with GSAP. 




I ended up using this for my purposes back then, too - it worked as it should have, and still does.


See the Pen GRPZwrJ by akapowl (@akapowl) on CodePen


  • Like 3
Link to comment
Share on other sites

Thanks @akapowl,

I used delayedCall as described:

gsap.delayedCall(.25, ()=> dlTimeline.play('contentin'));

and changed my logic from the following to use a isAnimating variable, which im setting to true/false:

if (lastTimeline && lastTimeline.isActive()) return;
if (dlTimeline.isActive()) return;

Thank you for all the input, also thanks to @Rodrigo again.


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