Generic Scroll Chaining Prevention Mechanism (or expand/standardize -ms-scroll-chaining)


#1

Problem

Scroll chaining is the process of propagating the scroll delta to the the nearest scrollable parent element once an scrollable reaches its limit. Scroll chaining is not always desirable. For example consider a fixed/absolute position scroller whose scroll should not chain to parent scroller i.e., the document. You can find this UX pattern used in most chat boxes that live at the bottom of the page such as in Facebook or Gmail UI. (See this chrome bug for example)

To give you a sense of how popular preventing scroll chaining may be, according to my quick http-archive search -ms-scroll-chaining: none is used in 0.4% of top 300K pages despite being limited in functionality and only supported on IE/Edge.

Current Solution

-ms-scroll-chaining is a vendor specific API which I believe is only supported by IE and Edge at the moment. The CSS property provides a simple declarative way to prevent propagation of scroll gestures to parent containers but unfortunately it is only limited to touch/touchpad scrolls. [1]

This means that currently the best cross-browser compatible way to prevent scroll propagation is to have a combination of blocking wheel event listener (bad for performance), blocking keyboard listeners for all scroll inducing keys, carefully crafted touch-action values, and perhaps even -ms-scroll-chaining. These are rather ugly and complex hacks that “-ms-scroll-chaining” should have been able to replace but it cannot in its current form.

Proposal

I think scroll-chaining is not really useful until it can be used to prevent scroll propagation in the general case. Enabling that will make it much more useful to web developers and thus more compelling for UAs to implement. So I propose the following changes to its semantic:

  1. scroll-chaining should apply to all user scrolls including mouse, touch, keyboard, and others. Programmatic scroll APIs such as Element::scrollIntoView are not affected by this.

  2. Scroll chaining be controlled independently for each axis. For example a component which does not overflow on horizontally should not prevent propagation on that axis if it only needs to prevent the vertical propagation. I suggest using scroll-chaining-{x,y} long-hands to match the overflow property.

Bonus Change

Specify what scroll-chaining means if it is added to the viewport defining element. Many browsers do navigation actions once user overscrolls the viewport. Lack of control over this behaviour has been a well-known pain for developers. We are experimenting with a new API to address this usecase but I think there is an opportunity here to leverage scroll-chaining here and avoid a slightly different API. For example, if chaining is disabled on viewport then it should disable navigation actions.

Note that (1) and (bonus change) may pose some compat risk however I feel these would be limited. We can try to better understand these risks once there is some consensus that these are useful changes.

Side Notes

I am not sure why scroll-chaining: none specifies a “bounce effect”. To me this looks like a user-agent specific affordance that does not need to be in the spec.

According to my tests the current definition is also bit out-dated compared to the current implementation in latest IE/Edge implementation. In particular, the property is not limited only to take effect during a manipulation but it also takes effect at the start of the manipulation. I think this is the right behavior anyways.

[1]

This property only applies to touch and touchpad input. Regardless of –ms-scroll-chaining value, for keyboard input the scroll does not chain, and for mouse input the scroll will always chain up to the nearest scrollable ancestor element.

[2]

Value that indicates the behavior that occurs when a user hits the scroll limit. chained : Initial value. The nearest scrollable parent element begins scrolling when the user hits a scroll limit during a manipulation. No bounce effect is shown. none: A bounce effect is shown when the user hits a scroll limit during a manipulation.


#2

@jacobrossi @teddink I would specially appreciate to know your take on this proposal. In particular, was there any specific reason as to why IE team decided to limit -ms-scroll-chaining to only touch/touchpad?

P.S. I should mention that I am a Chromium engineer and would be happy to drive this work from our end.


#3

I’ve created a demo and from what I see -ms-scroll-chaining is not supported in Edge or IE11. Could you check?

(To test, position the mouse cursor inside the yellow box and start scrolling with the mouse wheel; once you reach the end of the box, the browser should not “switch” to the main scrollbar.)


#4

Currently -ms-scroll-chaining is only applicable to touch and touchpad scrolling**. It has no effect on mouse wheel which is what you are testing. This is indeed one of the things I am proposing to change so that it applies to all scrolling.

** I verified that your demo works (i.e., chaining is disabled) with touch scrolling on a Edge/Win10/SurfaceBook combination.


#5

I like the proposal and agree with your proposed 1, 2 and bonus changes. The limitation of support to touch+touchpad is an implementation artifact and not by design. Agreed that the property should take effect both at the start and throughout the manipulation.

Agreed the “bounce effect” is implementation-specific and seems correct to omit that particular phrasing from the spec. However we may want to merge this solution with a solution for suppressing all UA-specific UI affordances when reaching the boundary of a non-chained scroller (we’ve received this request from multiple sources trying to improve their control over this behavior). So the 3 behaviors would be chain, resist chain with UI affordance, resist chain with no UI affordance. Doing so might point to alternative naming, maybe something like

scroll-boundary-behavior: scroll-parent | contain-scroll | none


#6

I like the proposal and agree with your proposed 1, 2 and bonus changes. The limitation of support to touch+touchpad is an implementation artifact and not by design. Agreed that the property should take effect both at the start and throughout the manipulation.

Great!

However we may want to merge this solution with a solution for suppressing all UA-specific UI affordances when reaching the boundary of a non-chained scroller (we’ve received this request from multiple sources trying to improve their control over this behavior)

I like this idea. Here is another example (related to elastic bounce effect on Mac OS) where controlling the overscroll UI affordance is desired.

Doing so might point to alternative naming, maybe something like scroll-boundary-behavior: scroll-parent | contain-scroll | none

How about: scroll-boundary-behavior: propagate | contain | none

  • propagate: propagate scroll to the parent scroller. If there is no parent scroller (e.g., viewport) user-agent may perform a default action (e.g. navigation) or show any appropriate overscroll UI affordance. This is the default value.
  • contain: do not propoagate. The user agent may show an appropriate overscroll UI affordance such as glow/bounce etc.
  • none: same as contain but also prevents any affordance UI affordance.

There will be scroll-boundary-behavior-{x,y} long-hands too.


#7

The name should probably be more different from the existing scroll-behavior, which has this constraint:

The scroll-behavior CSS property specifies the scrolling behavior for a scrolling box, when scrolling happens due to navigation or CSSOM scrolling APIs. Any other scrolls, e.g. those that are performed by the user, are not affected by this property.


#8

I still like “scroll-boundary-behavior” myself. I think whatever the name, this property belongs to CSSOM spec which also defines “scroll-behavior”. So I will opened an issue for CSSOM VIEW to see what its editor think about this feature and in particular if they have any objection/suggestion w.r.t naming.

I personally don’t think the fact that “scroll-behavior” is scoped to be limited to programmatic scrolls should prevent us to use ‘scroll’ and ‘behavior’ in other context where the scope is not limited to programmatic scrolls.


#9

I went ahead and created a github issue against CSSOM View to get its editors feedback on naming and it being the potential home for this feature.


#10

I’m working on a WICG repo for this issue. If you don’t mind I’d like to use your initial problem statement for the explainer.md. I should have something up in a few weeks or earlier.


#11

This is great to hear. Please feel free to use any of the material in this thread or on the github issue in the WICG repo. I am happy to collaborate as well.


#12

Looks like Benoit has a repo started here, thanks Benoit! CSSWG also recently resolved to work on this in WCIG. We’ll get the process started to move this to the WICG org.


#13

Incidentally, this repo has been renamed to match the new name - https://github.com/WICG/overscroll-behavior.


#14

Chrome 63 (current beta) should have support for overscroll-behavior, per chromestatus.