breadadams / scroller-motion

🛹 Elegant motion scrolling for React

Home Page:https://scroller-motion.js.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Option to not animate when scrolling page up to 0

rijk opened this issue · comments

I've been trying to fix this issue myself, but been getting pretty deep into the weeds, so I'll open up an issue here in case you have an idea how best to approach it.

When using Next.js, the page is wrapped in an App component that lets you do smooth page to page navigation. How this works (you probably are familiar with it), is it scrolls up after clicking a <Link> component. Normally, this makes it look like a 'normal' page refresh, as the scroll up happens at exactly the moment the content is changed. However, when using scroller-motion, the scrolling up is animated. This kind of ruins the illusion, and feels janky and jarring, as you see the contents of the new page flashing by.

For an example:

  1. Go to https://ray.care/story
  2. Scroll down
  3. Click the "Leer over onze ingrediënten" link
  4. Observe the next page’s contents flashing by

What I would like to have (what would be ideal), is an option to not animate scroll-to-top.

I've tried to achieve this using something like this:

image

to disable the animation by passing false as spring config (I also tried using disabled, but it rerenders the whole tree and resets the scroll position, so that won't work):

image

But this is really clunky and even triggers a React error from framer-motion:

image

Any ideas? 🙂

After trying a lot of roads, I got it working by using a spring with mass: .00001 while navigating (and afterwards reverting back to the normal spring). This both fixes the warning from framer-motion, and solves the issue where the useSpring() MotionValue might still be animating when switching back to it (so you'd need to add a setTimeout with an arbitrary value before switching back). I'm pretty happy with the mass solution, it's pretty clean and elegant.

const light = {
  mass: .1,
  stiffness: 60,
  damping: 30,
}
const off = { ...light, mass: .0001 }
<ScrollerMotion spring={( navigating ? off : light )}>
  {children}
</ScrollerMotion>

It's still not ideal; in some cases you can still see a one frame flicker happening while scrolling up. Also, because I have to track navigating in a state variable, this means the whole layout tree has to render twice. I can't think of any other way to solve this; even when I do my best to scroll up before the new page's <ScrollerMotion> is rendered, it still picks up the scroll and animates it.

Curious if you have any ideas for this.

(I also tried using disabled, but it rerenders the whole tree and resets the scroll position, so that won't work)

Hey @rijk, I'm doing some changes to the core of the library and I think I've resolved this issue, and we should be able to switch disabled on/off retaining the current scroll position and avoiding the re-render of the inner children.

Are you still using the library? If so I'll push a new release soon if you wish to try it out. Thanks for your patience 😇

Cool! Yes I am still using it 😄 www.ray.care

Awesome 🙌 , that site looks neat! Then watch this space, we'll get a new beta out tomorrow or Monday

This should be doable now with the v0.0.2 release, via the disabled prop.

Great, I'll check it out!

Hey @rijk, Can you share a bit about how you ended up approaching this? My scroll jumps during my transitions and it's quite weird. Using framer-motion and gatsby.

I don't know about Gatsby specifically, but you basically have to make sure disabled is set to true before you/Gatsby starts scrolling up as a result of a page change. In my case for Next.js, I have a layout component wrapping every page, with a useEffect like this:

const [ navigating, setNavigating ] = useState<boolean>( true )
useEffect( () => {
  window.scrollTo({ top: 0 })
  setTimeout( () => setNavigating( false ), 700 )
}, [] )

And then my ScrollerMotion has `disabled={mobile || navigating}` set.