Share Posted February 14, 2022 It is quite difficult for me to create a reproduction for this bug because it lives in a complex project. So I am asking for some possible directions/ideas that you can think of. Thanks! The animation is to stagger several elements on Y position - sliding from bottom of page to their original positions. Basically, the start position should be the top of the element's original position: But ScrollTrigger marked the start position way down the page, causing the animation not triggered until scrolled very far: I found this post, in which it was stated it's a bug: Here is the code that sets up these (I'm using it in React): const headerRef = useRef<HTMLElement>(null) const q = gsap.utils.selector(headerRef) useEffect(() => { const animation = gsap.from(q('.stagger_elements'), { y: '100vh', stagger: 0.05, ease: 'power4.out', scrollTrigger: { markers: true, trigger: headerRef.current, toggleActions: 'restart none none none', }, }) return () => { animation.kill() } }, []) And to add more context, it typically works on DEV mode on my local machine. Once deployed, the trigger position is often wrong but sometimes after several refresh, it could get it right occasionally. - that's why I tried to create a demo but cannot reproduce it. Could it be a bug? Any possible work arounds? I need the start position to be the element's original top (where the red arrow line is). Any ideas would be appreciated. Link to comment Share on other sites More sharing options...
Share Posted February 14, 2022 Hi nickraps, It's going to be really hard to advise on what the problem is without a minimal demo that clearly shows the issue. When someone says that it's too complicated to reproduce, it is even more even harder to advise because we don't know if something else in your code is messing with it. The only things that I can think of that would cause the positions to be incorrect. 1. Something is causing the layout to change after your ScrollTriggers are created, like say the height of an image after it loads, in which case you would need to call ScrollTrigger.refresh(). 2. You have triggers inside an element that gets pinned, causing the offset to be calculated incorrectly, in which case you would need to use pinnedContainer. Quote pinnedContainer Element | String - If your ScrollTrigger's trigger/endTrigger element is INSIDE an element that gets pinned by another ScrollTrigger (pretty uncommon), that would cause the start/end positions to be thrown off by however long that pin lasts, so you can set the pinnedContainer to that parent/container element to have ScrollTrigger calculate those offsets accordingly. Again, this is very rarely needed. (added in 3.7.0) 3. You are animating your triggers, which is going to put them in a different position. If that's the case, it's better animate a wrapper element instead. // bad gsap.to(myElement, { y: -500, scrollTrigger: { trigger: myElement } }); // better gsap.to(myWrapper, { y: -500, scrollTrigger: { trigger: myElement } }); Link to comment Share on other sites More sharing options...
Author Share Posted February 14, 2022 8 minutes ago, OSUblake said: 3. You are animating your triggers, which is going to put them in a different position. If that's the case, it's better animate a wrapper element instead. Thanks for these tips! @OSUblake I am animating the child elements in the root element, and the root element is the trigger. Would that be a concern? I'll try to create a reproduction demo too. Link to comment Share on other sites More sharing options...
Author Share Posted February 14, 2022 @OSUblake And to add more context, it typically works on DEV mode on my local machine. Once deployed, the trigger position is often wrong but sometimes after several refresh, it could get it right occasionally. - that's why I tried to create a demo but cannot reproduce it. Link to comment Share on other sites More sharing options...
Share Posted February 14, 2022 13 minutes ago, nickraps said: I am animating the child elements in the root element, and the root element is the trigger. Would that be a concern? Shouldn't be unless you have some weird pinning going on that React doesn't know about. Link to comment Share on other sites More sharing options...
Author Share Posted February 14, 2022 @OSUblake Yes, I think it is caused by a header that's pulled on the fly. The header renders an elements then quickly hides it - right when ScrollTrigger is calculating the positions. So the positions got pushed down the height of the header element. It is a mess anyway. I have no control over that header code. So in my case I'll probably just use GSAP for animation, but use something like intersection-observer for triggering it. Link to comment Share on other sites More sharing options...
Share Posted February 14, 2022 As Blake said earlier, just make sure you fire ScrollTrigger.refresh() when stuff in the DOM is settled so that it can do all its measurements accurately. No need to switch to IntersectionObserver, although that's totally fine if your needs are basic. It just can't do anywhere near what ScrollTrigger can do feature-wise Link to comment Share on other sites More sharing options...
Author Share Posted February 14, 2022 @GreenSock The difficult thing is the header is pulled from an ASP.NET HTTP web service from another server. I don't have access to any of that code. I can only call the HTTP service. So, I don't know if I can figure out a way to reliably know when I can refresh in the React UseEffect hook. I tried SetTimeout (which apparently is a bad solution) which delays long enough but causes issues for other things on the page. But thanks, I do agree ScrollTrigger is more powerful. 1 Link to comment Share on other sites More sharing options...
Share Posted February 14, 2022 3 minutes ago, nickraps said: but causes issues for other things on the page. You're saying that ScrollTrigger.refresh() causes issues on your page? Do you mind me asking how so? You could set up a setInterval() or something that checks for an effect you can predict with the header (like page height or the containing <div> height or something) and when it senses that change, you fire the ScrollTrigger.refresh() and kill the setInterval(). Just an idea. 1 Link to comment Share on other sites More sharing options...
Author Share Posted February 14, 2022 @GreenSock Oh Thanks for the hint! I just tried refresh() in a setTimeout and it seems to be working. And setInterval should be more reliable, will explore that later. So no, refresh() is good. I was putting the initialization code of the Trigger in setTimeout in a React component, so that it initiates after the header is fully rendered. But that causes other parts on the page that use this component to somehow not accurately calculate the positions or correctly initiate the Trigger. But now I see your hint, I realize I shouldn't initiate the Trigger in a setTimeout. Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now