Jump to content
Search Community

ScrollTrigger on sticky positioned elements breaks after resize

RoyG test
Moderator Tag

Recommended Posts

Hey,
Thanks for this amazing library! having a really good time with it!

I'm trying to implement a fairly simple scroll effect and I've noticed a weird behavior which I wasn't able to understand..

If you go to the attached codepen and scroll down, you'll see that there are a few elements with position: sticky that creates a stacking effect with the help of gsap.

You can see the problem by resizing the viewport (and scroll again) which for some reason breaks the scroll trigger and the stacking effect..


Any help appreciated :) 

See the Pen XWRZgJb by roygiladi (@roygiladi) on CodePen

Link to comment
Share on other sites

Hey @RoyG!

Welcome to the GSAP forums 🥳

I can't actually break it - maybe I'm resizing at the wrong time, but this scrollTrigger property is probably what you're looking for
 

invalidateOnRefresh Boolean - If true, the animation associated with the ScrollTrigger will have its invalidate() method called whenever a refresh() occurs (typically on resize). This flushes out any internally-recorded starting values.


Failing that you can specify different animations for smaller or larger screens like this...

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

  • Like 1
Link to comment
Share on other sites


Thanks for the fast response!

I've attached a recording demonstrating the issue, note how after resizing - the cards are animating together instead of one by one like it is before the resize..

Basically what the tweens does is scaling each card down as it approaches the top of the screen, each card is scaled abit different depends on it's position in the list (that what makes the stacking effect).

stacking.thumb.gif.0256465407ba8ba906be34bff0e119c5.gif
 

Link to comment
Share on other sites

Cool!

I've tried pinning with GSAP in the beginning but had no luck figuring out how to release the pins when the last card hits the end of the cards container (this happens automatically when using the native sticky positioning).

as you can see here, it just goes on top of the next section..

See the Pen dyWmYoN by roygiladi (@roygiladi) on CodePen



also, any idea or direction on why this problem happens when using sticky positioning with css?

Link to comment
Share on other sites

Ah, I see the problem now. 

 

When there's a screen resize, it triggers a ScrollTrigger.refresh() which basically means that ScrollTrigger has to undo any of its pinning and restore the page to its original state so that all your CSS/layout is implemented as expected and then it can redo all of its start/end measurements at that new size, then restore any pinning, etc. It intentionally doesn't force the scroll position back to the very top for various reasons (I can explain if you want...just ask). 

 

The reason position: sticky is contaminating things is because it affects the positioning of things in the normal document flow. So if, for example, you scroll far down to a point where a bunch of things are sticky and stacked on top of each other and then ScrollTrigger measures where all those elements are so that it can calculate the proper start/end scroll positions, the sticky stacking is throwing it all off. In other words, in the normal document flow (unscrolled) those elements may be 200px apart, so ScrollTrigger can map that properly to when they'd hit the top of the screen (or wherever). Maybe the 4th element would hit the top of the screen when the user scrolls 540px, for example. But with the page scrolled, position: sticky is a browser-level thing that's not undoable by ScrollTrigger in the same way that its own pinning can be undone, and those elements are in a totally different position and that 4th element may appear to only require 20px of scrolling to reach the top of the screen. 

 

See the problem? 

 

Don't worry - there's a solution. You could listen for a "refreshInit" event which occurs right before a refresh. Record the page's scroll position there, and then force it to the very top of the page (no scroll) so that all the measurements in the refresh are based on a non-scrolled page. Then in the "refresh" event handler, return the page to the proper scroll position. 

 

let scrollFunc = ScrollTrigger.getScrollFunc(window), // allows us to get/set scroll position
    lastScrollPosition;
ScrollTrigger.addEventListener("refreshInit", () => {
  lastScrollPosition = scrollFunc(); // record current scroll position
  scrollFunc(0); // reset it to 0 so that position: sticky doesn't contaminate measurements
});
ScrollTrigger.addEventListener("refresh", () => scrollFunc(lastScrollPosition));

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

 

Does that clear things up? 

  • Like 2
Link to comment
Share on other sites

Thanks, that totally makes sense!

The solution is pretty clever :) I just wonder how the scrollFunc(0) call doesn't actually scroll the window up? is it somehow synced internally by GSAP with the next   scrollFunc(lastScrollPosition) call?

Link to comment
Share on other sites

12 hours ago, RoyG said:

The solution is pretty clever :) I just wonder how the scrollFunc(0) call doesn't actually scroll the window up? is it somehow synced internally by GSAP with the next   scrollFunc(lastScrollPosition) call?

Yep, scrollFunc(0) DOES scroll the window all the way up. :)

 

You just don't see it because in the "refresh" event handler, we set it back to the lastScrollPosition. 

 

A refreshInit event gets fired right before ScrollTrigger does a refresh()...and then of course it fires a "refresh" event so it's all pretty seamless. 

 

Make sense?

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