Jump to content
Search Community

ScrollTrigger.refresh() awkward behavior

xoxoxoxo test
Moderator Tag

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

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

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

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