lenis icon indicating copy to clipboard operation
lenis copied to clipboard

CSR scroll behaviour tends to break while lenis is actively animating scroll value

Open damnsamn opened this issue 7 months ago • 5 comments

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.scrollTop or calling window.scrollTo do 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:

  1. The user scrolls some amount
  2. 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
  3. The router updates the route, and calls its window.scrollTo or equivalent to snap the window to the top of the new page
  4. 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.
  5. 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.

damnsamn avatar Apr 08 '25 07:04 damnsamn

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

clementroche avatar Apr 08 '25 08:04 clementroche

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?

damnsamn avatar Apr 08 '25 14:04 damnsamn

For anchors, you can just use the anchors option

Image

clementroche avatar Apr 08 '25 14:04 clementroche

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)
}

clementroche avatar Apr 08 '25 14:04 clementroche

For anchors, you can just use the anchors option

Image

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);
})

damnsamn avatar Apr 08 '25 15:04 damnsamn

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.

A-AKB avatar Jun 21 '25 03:06 A-AKB

@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

slavanga avatar Oct 23 '25 12:10 slavanga

Hello @slavanga, nice catch. Let me fix that ASAP

clementroche avatar Oct 23 '25 13:10 clementroche

hello @slavanga, i've just published a new version of lenis/framer, can you check?

clementroche avatar Oct 25 '25 17:10 clementroche

Hey @clementroche Thank you for the quick fix! Looking good on my end 🥳

slavanga avatar Oct 26 '25 08:10 slavanga