Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
xoxoxoxo

ScrollTrigger.refresh() awkward behavior

Recommended Posts

I have awkward behavior in nextjs on route changes. When the route changes successfully, I explicitly call `window.scrollTo(0,0)` to reset the scroll position of the browser.

 

However, on a new page route I'm creating a scroll trigger and also refreshing it which yields into a negative side effect of retaining the previous route's scroll position. does ScrollTrigger.refresh(true) retain the scroll position internally?


Thanks.

Link to comment
Share on other sites

I've disabled all scroll controls Nextjs ships with so i'm pretty convinced that it's not the framework.

 

I tried fiddling with ScrollTrigger's source code and adding an early return here, which does not retain the scroll position on route changes. This fixes the issue I'm having on route changes however I can't understand where and why it's being called during runtime.

 

Why is it calling scrollTo? The value arg seems to be the y position of the previous route in my case. Is there a source with comments to understand this better?

 

sc: function sc(value) {
if (arguments.lengthreturn;
return arguments.length ? _win.scrollTo(_horizontal.sc(), value) : _win.pageYOffset || _doc[_scrollTop] || _docEl[_scrollTop] || _body[_scrollTop] || 0;
}
Link to comment
Share on other sites

Are you sure you called kill() on all the ScrollTriggers before you do your route change? Like ScrollTrigger.getAll().forEach(t => t.kill())

 

ScrollTrigger needs to record the page's scroll position when it does its refresh because it must roll back all of its changes to ensure that all the styling is back to "normal" when doing the start/end calculations. Remember, if you have any pinned elements, they typically add padding and stretch out the page. For example, your native page might be 1000px tall but if you pin an element for 5000px, now your page is 6000px tall, so if you scroll down 3000px and then refresh the browser, it has to restore that after it does all of its teardown & calculations. Otherwise, a 1000px page can't possibly scroll to 3000px natively. See what I mean? But ScrollTrigger has code in place to flush that recorded value if you kill() all your ScrollTriggers. My guess is you forgot to do that(?)

Link to comment
Share on other sites

I do kill ScrollTrigger on an individual level rather than all on route change. The return function gets called when component unmounts.

 

React.useEffect(() => {
if (ref.current == null) return;
 
const st = ScrollTrigger.create({
trigger: ref.current,
pin: true,
start: 'top top',
pinSpacing: false,
});
 
ScrollTrigger.refresh(true);
 
return () => st.kill();
}, [pageStyle]);
Link to comment
Share on other sites

Perhaps the rollback should respect browser's history scrollRestoration property before calling scrollTo?

Link to comment
Share on other sites

I had the exact same situation (with Vue.js). I kill'ed the ScrollTrigger when my component was about to die (onBeforeUnmount). But it turned out that it's too late.

Using the above advice (ScrollTrigger.getAll().forEach(t => t.kill())) before route changes solved it for me.

Link to comment
Share on other sites

Don't know if this will help because you didn't provide a minimal demo, but you should create and kill your ScrollTriggers with useLayoutEffect. That will also fire a tad earlier than useEffect.

Link to comment
Share on other sites

If the unmount happens after route has completed then it doesn't really matter if you're using useLayoutEffect or not.

 

See the log below. Unmount triggers after the route has completed which means the initial page has already rendered.

 

I still think the rollback on refresh should respect browser's scrollRestoration property before calling scrollTo method.

 

image.png.a74e7db8cb282b280fc537b6909d6a41.png

Link to comment
Share on other sites

Can you please make a minimal demo with those logs. It looks like there is a solution.

Link to comment
Share on other sites

13 hours ago, xoxoxoxo said:

Perhaps the rollback should respect browser's history scrollRestoration property before calling scrollTo?

I don't really see how that'd help. The point here is that when ScrollTrigger does a .refresh() it must record the current scroll position and then when it's done with all its work, restore that. We do plan to add a new ScrollTrigger.clearScrollMemory() method in the next release which will let you manually do it. 

Link to comment
Share on other sites

I'm using the new api on unmount right after I kill the scroll trigger ScrollTrigger.clearScrollMemory() and it seems to work.

  • Thanks 1
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.
×