motion icon indicating copy to clipboard operation
motion copied to clipboard

[FEATURE] useScroll + useSpring : optional animate on refresh

Open RemiGirard opened this issue 11 months ago • 1 comments

Is your feature request related to a problem? Please describe. When using useScroll and useSpring together, if you have some scroll progress then, on page refresh the default behavior is : the animation restarts from 0 scroll and animate progressively to match scroll value. Another wanted behavior can be : be directly on the proper value after refresh and only animate on scroll change.

The default behavior can be observed on this documentation example (try to scroll a bit, then refresh, you can see the animation) : https://examples.motion.dev/react/scroll-linked-with-spring

This behavior is not only on refresh but also if user click a link and then press back on browser.

Describe the solution you'd like Some users would like to have the animation restart on refresh and in some cases not, so the solution could be :

  • having an option to start on current scroll : useScroll({startAtZero: false})

I think the default behavior should be the same, to don't break any existing wanted behavior.

Currently, it seems on useScroll, the value always starts on zero: https://github.com/motiondivision/motion/blob/0a83d4e95889d3d7e216c5b41b656dd6b5ff01b1/packages/framer-motion/src/value/use-scroll.ts

Describe alternatives you've considered Current alternative can be :

  • hide element until animation finish
  • + replace animation with useScroll without useSpring until starting animation is finished

Additional context

Current default behavior

Start

start

Scroll

scroll

Scroll + refresh + 0 sec

scrollRefresh0Sec

Scroll + refresh + 1 sec

scrollRefresh1sec

optional {startAtZero: false} behavior

Start (same)

start

Scroll (same)

scroll

Scroll + refresh + 0 sec (already on current value)

scrollRefresh1sec

Scroll + refresh + 1 sec (same)

scrollRefresh1sec

RemiGirard avatar Mar 10 '25 14:03 RemiGirard

I also encountered this behavior and found it to be unexpected. When the page starts scrolled, the jump from scroll=0 can cause pretty massive initial velocities can be calculated. This can be particularly problematic when attempting to smooth out the scroll velocity with a spring.

This happens inconsistently but regularly, and the update can take 1-3 frames to apply. Two imperfect solutions I've tried that seem to mitigate the issue are either syncing the actual scroll position manually for those frames, or forcing the velocity to be 0 for those first few frames.

Example code of that second approach:

const { scrollY } = useScroll();
const rawScrollVelocity = useVelocity(scrollY);

// The actual scroll velocity used in the app
const scrollVelocity = useMotionValue(0);

useAnimationFrame((t) => {
  // Only sync the values after a few frames to avoid the page-load
  // velocity spikes caused by consuming useScroll directly
  if (t > 50) {
    scrollVelocity.set(rawScrollVelocity.get());
  }
});

It's possible this code will occasionally still show the unexpected behavior.

jamesplease avatar Mar 26 '25 02:03 jamesplease