lenis
lenis copied to clipboard
CSR scroll behaviour tends to break while lenis is actively animating scroll value
We're encountering an issue on our site where sometimes, when you click a link, it'll take you to part-way down the linked page, rather than snapping to the top. I've narrowed the "sometimes" down to "while lenis is animating scroll".
The core problem seems to be:
- It seems like setting
window.scrollTopor callingwindow.scrollTodo not function whilst lenis is currently animating scroll - CSR (eg Next router) will manually call some variation of
window.scrollTop(0,0)when a routing change occurs
The sequence in practice looks something like this:
- The user scrolls some amount
- While the scroll value is still lerping (typically while it's eased to be single-digit or fractional pixels per frame), the user clicks a link
- The router updates the route, and calls its
window.scrollToor equivalent to snap the window to the top of the new page - Since lenis is still hijacking the scroll value, the scroll value does not snap to the top. It instead maintains its lerp to the original target scroll position (which might be greater than the new page's total
scrollHeight), but now within the context of the new page. - The end result is the user is now scrolled partway down the new page.
This issue should be replicable on any project that uses some degree of client-side routing.
It makes sense since window.scrollTo() cannot interrupt lenis scroll, there is two way to handle that:
- init/destroy one lenis instance per page
- reset lenis scroll manually on page change
My current hacky solution today was just to call lenis.stop(); lenis.start(); on click
Manually setting lenis to scroll to the top each route change would be the most robust solution on the consumer end, but would also require manually handling anchors etc.
Could it be possible to provide lenis a config option to respect window.scrollTo whilst animating in the future?
For anchors, you can just use the anchors option
This would require to overwrite window.scrollTo API, it could be interesting
const originalScrollTo = window.scrollTo
window.scrollTo = (x,y,options={}) => {
lenis.reset()
originalScrollTo(x,y,options)
}
For anchors, you can just use the
anchorsoption
I think what I mean is that by manually setting scroll position on route, we'd also be opting out of anchor scrolling (even using the anchors option) unless I am mistaken.
Consider the following react code, doing something like this would (I imagine?) override any anchor scrolling, either natively or provided by lenis
useOnRouteChange(()=> {
lenis.scrollTo(0);
})
Hi,
Still having this issue with Next.js 15 and Lenis 1.3.4. When I click links while the page is still smoothly scrolling, it takes me to the wrong position on the new page instead of the top.
This creates really bad UX on production sites - users expect to land at the top of new pages.
While there are several workarounds floating around (like lenis.scrollTo(0, {immediate: true, force: true}) or stopping/starting Lenis on route changes), these feel hacky and shouldn't be necessary. This is a core navigation issue that affects the fundamental user experience.
@clementroche Same thing happens in Framer. What would be the recommended fix there? Any way to bake a fix into the component?
See demo here: https://glad-designs-825634.framer.app/test
Hello @slavanga, nice catch. Let me fix that ASAP
hello @slavanga, i've just published a new version of lenis/framer, can you check?
Hey @clementroche Thank you for the quick fix! Looking good on my end 🥳