scroll-snap icon indicating copy to clipboard operation
scroll-snap copied to clipboard

Add option to listen to `touchstart` / `touchend` events and only snap on `touchend`

Open lucafalasco opened this issue 5 years ago • 5 comments

Css Scroll Snap spec waits for "touchend" event before snapping, would be useful to add this behaviour as an optional parameter.

Originally posted by @lucafalasco in https://github.com/lucafalasco/scroll-snap/issues/23#issuecomment-650107410

lucafalasco avatar Jun 26 '20 10:06 lucafalasco

@lucafalasco I can take a crack at this, do you have some guidance on where to start?

My initial approach would be to, if you passed the appropriate prop for this behavior to be enabled, to pass a flag to startAnimation that would allow it to initially detect direction of scroll (on touchstart) and then to snap (on touchend).

Do you agree with that? Good place to start?

zkwentz avatar Sep 17 '20 17:09 zkwentz

Quick update @lucafalasco: I've looked at this more closely and I have an approach (PR to come this weekend). The approach is for, if a prop is passed (I'm assuming you would pass this based on device detection), the touchend event would be a flag that would not allow animation's timeout to run until it is true.

I also did a bit of exploration around why iOS is problematic with scroll snap in certain cases (you have a small amount of content you are scrolling or you have a lot of snap points) and I've found it's the gravity with iOS's scroll. After you touchend, the scroll sort of continues and so your animation begins, but the native scroll is still ending, it kicks off another animation (in the other direction now) and you end up in this infinite scroll situation.

In light of the above, while I think this touchend approach is a mitigating factor, I'm also going to need to explore how to get rid of that ending gravity with iOS scroll.

More to come (happy for feedback by the way if you had a different approach in mind).

zkwentz avatar Sep 18 '20 14:09 zkwentz

Hey @zkwentz, First of all thanks for your feedback on this!

So, what I was initially thinking is that we could add additional mouse and touch events to handle both cases (scrolling with a desktop scrollbar or using a finger on touch devices) and prevent the scroll snap to take action as you were saying.

I imagine something like:

this.listenerElement.addEventListener('mousedown', onTouchStart)
this.listenerElement.addEventListener('touchstart', onTouchStart)
this.listenerElement.addEventListener('mouseup', onTouchEnd)
this.listenerElement.addEventListener('touchend', onTouchEnd)

should take into account all the possible cases.

Ideally onTouchStart could update a variable (call it isSnapPrevented for example) we can later use to prevent the scroll snap and restart the timeout until onTouchEnd gets called and the variable gets reset.

This way we shouldn't even need to detect the device nor pass any additional config property, because the variable would only be changed if any of the events get triggered.

On a side note, I agree momentum scrolling on iOS devices caused troubles and that was why I initially tried to fix that by using overflow scrolling, but it ended up breaking other things after some time.. so I ended up increasing the minimum scroll timeout to wait for the momentum to finish. I think adding the touch event handler could fix any issues left with iOS though.

Let me know if that was clear and I'll be happy to review the PR!

lucafalasco avatar Sep 22 '20 11:09 lucafalasco

Ahh, great point, I only really need the flag and the additional listeners because of the timeout. Even less invasive!

Okay, PR coming soon.

zkwentz avatar Sep 24 '20 00:09 zkwentz

Did you ever finish this PR?

supermoos avatar Jan 13 '22 09:01 supermoos