Jump to content
Search Community

ScrollTrigger based animation inside a pinned container is not consistent upon reload or when scrolling fast.

Krishnakant test
Moderator Tag

Recommended Posts

Hi,

 

I am struggling to get this right - its very frustrating to see the animations behave in inconsistent manner in this scenario. I have a pinned container with some cards in it. I want to

  1.  Animate the cards initially to show up at some point (after the container is pinned) without scrub and with stagger.
  2.  Animate them one by one from the previous state, after a brief pause without scrub (based on the scroll position) when scrolled through the pinned container.

The issues I am having (although its not visible sometimes in CodePen but clearly visible in actual webpage) are

  1. When page is reloaded (especially when in between the pinned container while reloading) the animation sequence either doesn't play at all (cards don't move at all) or very inconsistent. It doesn't start where it left or suddenly jump.
  2. The similar things happen when scrolled fast back and forth. They overlap, with the cards placed somewhere in between. (here is a screenshot of the same - https://ibb.co/18nVwtk

 I am still learning about ScrollTrigger and hence I am not sure what is wrong with my code here, or how can it be fixed. Please guide me.

See the Pen dyrYXzx by designjuice (@designjuice) on CodePen

Link to comment
Share on other sites

Yeah, that's a logic thing in your code - you've set it up so that you've got multiple tweens running on the same element in totally different directions at the same time. No bueno. 

 

Also, keep in mind that .to() and .from() tweens use the CURRENT value for one of the ends of the to/from animation. Those get recorded when the tween runs for the first time.  For example, if obj.x is at 0 to begin and you animate to x: 100, it will use the current value (0) as the start. But if another tween is animating obj.x when that 2nd tween first renders, maybe obj.x is at 12.245 at that particular moment - that 2nd tween will lock in the starting value as 12.245 and animate to 100. If you reverse() that tween, it'll of course end at 12.245. 

 

If you really need to have overlapping/conflicting tweens like that, I'd recommend setting it up in a more dynamic way so that it'll just always animate to the most recent end value that you want, and set overwrite: "auto" (or true, depending on what effect you want). 

 

Maybe something like this: 

See the Pen eYXpyYx?editors=0010 by GreenSock (@GreenSock) on CodePen

 

I hope that helps. Have fun!

Link to comment
Share on other sites

Hi,

 

Thank you for clarifying on the logic. Really helpful.

 

However, I want to have the animation of cards to be sequential rather than overlapping as I said. I want the cards to animate from bottom to start with (when scrolling down at some point) and then drift away one by one to the top after a short pause. And reverse the same when scrolling up. That's why I thought of toggleActions which could work in this case. But your code/logic made me think further to use callback functions (with custom logic) - which I am not familiar with at the moment. I will have to think again on, when to use callbacks and not toggleActions. Anyways, I will implement it in my actual webpage to see if it resolves the inconsistency.

 

Further, I observed that sometimes (when scrolling fast from top to bottom and further up) one card remains there (the top one, which is not what I want) - and sometimes it doesn't, exactly at the same scroll position. Please have a look at these screenshots to know what I mean. https://ibb.co/3chg18S      https://ibb.co/qMyMxd8. Do you think this is a issue with logic or something else?

 

Please guide me on this, appreciate your help and patience in explaining the concepts. Thank you so much.

Link to comment
Share on other sites

Yep, it's all pure logic issues. Imagine you scroll down and then back up rather quickly. So your onLeaveBack() fires for the first card: 

 gsap.timeline()
  .to(card, {
    duration: 1, 
    ...
  }).to(card, {
    y: 0,
    duration: 0.8,
    overwrite: "auto"
  }, '-=0.2');

That means the card's "y" won't start animating for 0.8 seconds. But we keep scrolling back to where this gets triggered: 

gsap.to('.card', {
  y: 1000,
  duration: 1,
  stagger: {
    amount: 0.5,
  },
  overwrite: "auto"
});

So this one starts IMMEDIATELY animating that same element's y back to 1000 (this is where we want it to land at this point), and overwrite: "auto" means that it'll only find IN-PROGRESS tweens of the same property of the same element and kill those...but remember that the previous one we started would WAIT 0.8 seconds before beginning...so it hasn't started yet, thus it won't get overwritten. 

 

0.8 seconds later, that [old] tween starts animating card.y back to 0!

 

See the problem? 

 

You could set overwrite: true on the main staggered animation so that it immediately overwrites any tweens of that same element, regardless of if they're in-progress or not. 

 

Again, this is all just logic stuff. I hope that clears things up. 

  • Like 1
Link to comment
Share on other sites

Hi,

 

Thank you again for clarifying on the issues in the implementation of logic. The solution works well in the CodePen, but I observed a strange issue with Pinned container in my actual project. Unfortunately this does not happen in CodePen and I don't know how can I explain it well enough for you to understand. But let me try.

 

Whenever I am scrolling with container pinned, and like 1 or 2 of the 4 cards have already animated (to the top), if I refresh the page at that very point, and when the page reloads, it doesn't seem to start from that particular point - say for example, when container gets pinned and all the cards animate to the top with stagger, and then I scroll further to animate first card to the top, then I refresh the page, it logs card's index "0 enter" but the card will be still there. And when I scroll further, the next card starts animating with the first card still there.

 

To investigate on this issue I commented out all the code keeping only the pinned trigger, initial set method for cards and the main ScrollTrigger for staggered animation of cards like below mentioned code. To my surprise, this didn't work as well - it works fine when I have not scrolled to the pinned section and reload, but when I try to reload the page after scrolling into the pinned section the trigger markers jump to some unimaginable point(usually at the very top of the page), not at all at the same point before reload. And the cards animation stops there because the it will never hit the trigger.

 

Upon carefully observing this, I saw a strange jumping behavior of scrollbar thumb whenever page reloads, it goes up once and then come to the original position or vice versa sometimes. In CodePen it always stayed at the top on refresh, although I don't have any specific code to scroll to the top on reload, but this is how it is.

 

To check it further, I commented-out the pinned container ScrollTrigger and the reloaded the page - to my surprise, this time the scroll thumb was not jumping up and down at all, it stayed there no matter whatever the scroll position is. So, pinning the container is causing the issue here.

 

I hope I made myself clear about the issue I am facing here, unfortunately I am not able to show this very awkward behavior with pinned sections. And I do not have any clue on how do I resolve this. Please help.

ScrollTrigger.create({
    id: "pinned",
    trigger: '.pinned',
    start: 'top top',
    pin: true,
    end: "+=" + pinDistance,
});

gsap.set(cards, {
	y: 1000,
	rotate: (index) => -angle * index,
	zIndex: (index) => cards.length - index,
});

ScrollTrigger.create({
  trigger: '.cards_wrap',
  start: 'top top',
  end: 'bottom bottom',
  // markers: true,
  onEnter() {
  	console.log("enter");
  	gsap.to('.card', {
  		y: 0,
  		duration: 1,
  		delay: 0.5,
  		stagger: {
  		amount: 0.5
  	},
  	overwrite: true,
  });
  },
  onLeaveBack() {
  	console.log("leave back");
  	gsap.to('.card', {
  		y: 1000,
  		duration: 1,
  		stagger: {
  		amount: 0.5,
  	},
  	overwrite: true
  });
  }
});
Link to comment
Share on other sites

It's virtually impossible for us to troubleshoot blind - can you provide a CodePen or Stackblitz that illustrates the problem? I wonder if you're lazy-loading images or something where ScrollTrigger calculates the positions and THEN images load and push everything down on the page. I'm totally guessing. You said the CodePen works fine, though, right? 🤷‍♂️

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