Skip to content

[css-scroll-snap-2] Should scrollsnapchanging target the currently visible element during flings #10838

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
flackr opened this issue Sep 5, 2024 · 9 comments

Comments

@flackr
Copy link
Contributor

flackr commented Sep 5, 2024

The css-scroll-snap-2 spec says the following about scrollsnapchanging:

A scrolling operation might animate towards a particular position (e.g. scrollbar arrow clicks, arrow key presses, "behavior: smooth" programmatic scrolls) or might directly track a user’s input (e.g. touch scrolling, scrollbar dragging). In either case, the user agent chooses an eventual snap target in each axis to which the scroller will snap after the scrolling operation reaches its intended scroll position.

In the former case, the intended scroll position is the scroll animation’s target scroll offset.

In the latter case, the intended scroll position is the current scroll offset as determined by the user’s input.

For the case where the user is or was interacting and initiated a fling, Chrome determines the eventual snap target which can mean that we immediately dispatch a scrollsnapchanging event for the location the scroll will eventually land even if it will pass over the areas which would normally snap to other elements first. This was called out in the Scroll Snap Events article and is illustrated by several of the demos such as the scrollsnapchanging visualizer demo.

Note that the spec text does not seem to imply this behavior - since it says in the latter case referring to cases where it "might directly track a user's input (e.g. touch scrolling, scrollbar dragging)" that it is intended to use the current scroll offset, so it would seem that my desired outcome might match the spec but not chrome.

I think for cases where you have clicked on an anchor link and we are executing a smooth scroll to a predetermined location, using the eventual target is a better experience than flipping through all of the snap targets as they fly by (demo), however, during a scroll interaction having the tracked item switch from on screen (while the finger is down) to the eventual target offscreen after you lift your finger and start a fling feels unintuitive to me (e.g. fling in the previous demo or this ruler demo for a more obvious example where it feels unintuitive).

@flackr
Copy link
Contributor Author

flackr commented Sep 5, 2024

I think @argyleink would prefer to see a different event for this.

@argyleink
Copy link
Contributor

yeah, the most common description among my queried community was "fly over", but the technical term is closer to "scrollSnapAxisCross" or "scrollSnapOverAxis".

I do think this is a nice addition, it's in-between the current features in terms of information, and it does open up the information that's otherwise private or hard to decipher for authors.

question: is intersection observer already built for this purpose?
intersection observer works on area intersection, while this event is oriented more towards axis intersection. but couldn't the area of the IO be created to be thin and tall, like an axis? regardless, a simple and easy to use callback for axis crossing would be nice to have.

@flackr
Copy link
Contributor Author

flackr commented Sep 5, 2024

Do you have particular use cases for which you think that the current behavior on flings is better? Or are they the ones in those demos? In my experience, I haven't seen websites or native applications where a fling predicts the destination beyond the next item. Maybe we could prototype whatever the most compelling use cases are and spot check / vote whether the current behavior or my proposed change is better or whether there are use cases for both?

@argyleink
Copy link
Contributor

Do you have particular use cases for which you think that the current behavior on flings is better?

i think almost all of the examples are better with the current behavior, except maybe the ruler.

In my experience, I haven't seen websites or native applications where a fling predicts the destination beyond the next item.

agree, me neither. but i also don't think that makes them better, but it does mean it's more familiar. animation-timeline: view() is maybe closer to what they're using too, instead of callbacks/triggers? the ruler uses a combination of them, but does reserve the "current indicator" visual effect not scroll driven; i felt it made the UI selected item feedback stand out.

Maybe we could prototype whatever the most compelling use cases are and spot check / vote whether the current behavior or my proposed change is better or whether there are use cases for both?

you know my feelings about prototypes! they can speak 1000 words. let's do it.

there are use cases for both

i think if i used view() and specified a small animation range that matched the axis area, i could listen for animationend on the snap items and simulate getting a callback like this scrollSnapOverAxis would add. also think IO could help us too, but be more manual work to isolate the intersection.

random thoughts
the unique aspects of this event is that it fires more eagerly than the other 2 events.
it would also fire at the same rate as scrollsnapchanging for nearly all user interactions except a fling. it's the same as the others in that it'd be useful for scroll triggered animation, from either CSS or JS. last random thought, I wonder if folks would debounce or throttle this event because it was so eager? I feel like the current scrollsnapchanging event is modern in it's take, smarter and less wasteful, like an evolution that required "prediction" information which maybe wasn't available in older API implementations.

@flackr
Copy link
Contributor Author

flackr commented Sep 6, 2024

animation-timeline: view() is maybe closer to what they're using too

Right, this would produce the expected behavior for flings, but it would mean that clicking on an anchor link, e.g. the 5 in my demo would also slowly step through each element, delaying the feedback that you have selected the 5th page. For targeted scrolls, it makes sense that the user has an expectation about where it is going and so expects immediate feedback about the target location.

I have two main concerns about predicting the fling:

  • It's not continuous. The instant you lift your finger to start the fling the snapchanging target immediately shifts to something many elements away from it. This discontinuity gives me the impression that there was a bug or unexpected jump.
  • Unlike targeted scrolls, for momentum scrolls the user usually doesn't understand where they've scrolled to, and it's a fairly chaotic location (subject to minor differences in fling speed).

I'll prototype something up to make it easy to compare the two which I think will help with deciding on one of three outcomes:

  1. Fling momentum prediction is better, we should ensure it is spec'd.
  2. Not predicting fling momentum scrolls is better, we should change chrome
  3. Each has their use cases. We should figure out how an author should choose they want.

@flackr
Copy link
Contributor Author

flackr commented Nov 27, 2024

Okay, I've put together a demo that lets you compare two strategies for scrollsnapchanging (use chrome canary with experimental web platform features enabled):
https://flackr.github.io/web-demos/css-scroll-snap/scrollsnapchanging/index.html

In the demo, you can select from:

  1. Native: This uses the platform scrollsnapchanging events - e.g. in chrome canary this is currently the predicted end of scroll location.
  2. None: Turns off that highlight
  3. Current location: Closest snap point based solely on the current scroll location
  4. Targeted location: Uses the targeted location of a programmatic scroll call, but otherwise uses closest.

I propose that the targeted location is better than the current native behavior. In particular, when you fling the native behavior jumps ahead by several items quickly. Using the targeted location instead of always using the current location is necessary to ensure that clicking on a particular location immediately selects it.

@argyleink
Copy link
Contributor

Thanks for the demo, so nice to feel these things out.

Targeted location 👍🏻

@bramus
Copy link
Contributor

bramus commented Dec 11, 2024

+1 on Targeted Location

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-scroll-snap-2] Should scrollsnapchanging target the currently visible element during flings, and agreed to the following:

  • RESOLVED: scrollsnapchanging uses the targeted location for targeted scrolls, but does not predict the destination of momentum scrolling (uses the current scroll location instead)
The full IRC log of that discussion <TabAtkins> flackr: we defined scrollsnapchanging as using the "eventual scrol lpositition". this makes sense for targeted scrolls, but is confusing when flinging.
<TabAtkins> flackr: we'll predict a position far out, but if you change your scroll velocity the identified item jumps back to the one currently in view
<TabAtkins> flackr: proposing we change the behavior so that targeted scrolls (where we know the intended destination) that we use that target (as the spec already says), but for momentum scrolls we use the current position, as if you're actively scrolling and we don't know where you'll end up
<TabAtkins> flackr: this is more intuitive, where the identified item doesn't jump ahead of your scroll
<TabAtkins> +1, this sounds right. I'd expect indicated element to gradually move as the fling progresses
<TabAtkins> astearns: are you going to be able to tell what kind of things you're getting back?
<TabAtkins> astearns: targeted vs currnet scroll position?
<TabAtkins> flackr: API doesn't differentiate, you just get a currentTarget
<TabAtkins> flackr: for all the use-cases we've been talking about this feels right, but it's possible we might want something always based on the current location.
<TabAtkins> flackr: doesn't make sense to have something always based on target location; sometimes you don't have a different target location.
<TabAtkins> flackr: but if we eventaully wanted one for the currently-in-view thing even during a targeted scroll, we could add it
<TabAtkins> astearns: i don't have a particular reason to need it, was just wondering
<TabAtkins> flackr: yeah, for all use-cases we know - carousel, selected UI - it makes sense to use current or target as i'm proposing here, depending on type of scroll
<TabAtkins> astearns: other questions?
<TabAtkins> astearns: summary?
<TabAtkins> flackr: proposed resolution: scrollsnapchanging uses the targeted location for targeted scrolls, but does not predict the destination of momentum scrolling (uses the current scroll location instead)
<TabAtkins> RESOLVED: scrollsnapchanging uses the targeted location for targeted scrolls, but does not predict the destination of momentum scrolling (uses the current scroll location instead)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants