W3C home > Mailing lists > Public > public-css-archive@w3.org > July 2019

Re: [csswg-drafts] [css-scroll-snap-1] Compat between webkit and blink/gecko regarding "implicit" scroll boundary snap positions (#4037)

From: Justin Grant via GitHub <sysbot+gh@w3.org>
Date: Sun, 14 Jul 2019 18:26:06 +0000
To: public-css-archive@w3.org
Message-ID: <issue_comment.created-511224794-1563128764-sysbot+gh@w3.org>
_TL;DR: creating implicit scroll positions at scrollmin/scrollmax breaks a popular web-performance technique: Virtual Scrolling. If we don't standardize on "no implicit scroll positions" (the current Blink/Gecko behavior), then IMHO we'd need another way to enable Virtual Scrolling to work with scroll snapping. Details are below._

The current WebKit behavior (creating implicit snap positions at scrollmin/scrollmax of the container) [breaks](https://github.com/bvaughn/react-window/issues/290) "Virtual Scrolling" implementations like Facebook's [react-window](https://github.com/bvaughn/react-window) that use JavaScript to simulate a long, scrollable list of thousands of items without the overhead of creating thousands of DOM nodes.  This technique has been popular for many years because it's a good way to reduce the initial render time (and client RAM footprint and server data-fetching) of long lists without the complexity of having to roll your own scrollbar UX and scroll behavior, which is really hard to get right and is expensive to maintain. Especially on touch devices.

Virtual Scrolling implementations work like this: 
* A "List" element with `overflow: scroll` (or `auto`) contains a "Scroller" element that's very long and mostly empty except for a few absolutely-positioned "Item" elements.
* On initialization, the implementation creates and positions Item elements to cover the List's viewport, plus a few extra items on either side of the viewport to avoid gaps showing when slow scrolls happen.
* The implementation listens for scroll events, and when the user scrolls, the implementation JIT-creates new Item elements in ahead of where the user is scrolling. If the user scrolls slowly, no gaps will be seen because Item elements will have been added & positioned by the time the user scrolls to them. If the user scrolls quickly, then the Scroller background may show for a few tens of msecs before the new items are painted.

You can see an example of Virtual Scrolling here: https://codesandbox.io/s/happy-architecture-m7pn5. The top list uses Virtual Scrolling.

Unfortunately, WebKit's behavior that defines implicit snap positions at the scrollmin/scrollmax breaks these virtual list components if scroll snap is enabled. A fast (flick/momentum) scroll on Safari will scroll to the end of the content before the Virtual Scrolling script has a chance to place new Item elements at the user's new scroll position.  Repro steps are here: https://github.com/bvaughn/react-window/issues/290.

I can think of many possible ways to address this problem: 
1.  Standardize Blink's/Gecko's behavior: don't create implicit scroll points at scrollmin/scrollmax. I like this option because it seems like the easiest way for developers to add scroll snapping to a Virtual Scrolling list.
2. Add a new CSS property for scroll containers, e.g. `scroll-snap-implicit` or `scroll-snap-edge` with possible values `start`, `end`, `both` (current Blink/Gecko behavior), and `none` (current Blink/Gecko behavior).  I'd lobby for the default to be `none` because it'd minimize changes needed to existing code, but adapting existing code to a default of `both` wouldn't be a huge problem.
3. Extend `scroll-snap-type` with the values from (2) instead of adding a new property, e.g. `scroll-snap-type: x mandatory none` or `scroll-snap-type: x mandatory both`.
4. Add a new CSS property to describe how children of a parent element are expected to be populated, e.g. `child-population` with values like: 
    a) `sparse-dynamic` - virtual scrolling list (don't create implicit scroll points at scrollmin/scrollmax)
    b) `dynamic` - dynamically populated but non-virtual list, aka "infinite scroll" like on Twitter.
    c)  `static` - no dynamic population expected
    d) `default`- no assumption about how child elements will be populated
The idea would be to provide UAs with higher-level metadata about how a container is expected to be populated, and UAs could optimize various features accordingly (e.g. batched rendering for dynamic lists). Honestly this feels like overkill to fix a scroll snapping problem, but I'm including for completeness.
5. Some other workaround I haven't thought of that leverages existing CSS properties.

I'm sure there are other options too. The only option that is IMHO *not* OK: requiring implicit scroll points at scrollmin/scrollmax (the current WebKit behavior) without some other way to ensure that Virtual Scrolling containers will work with scroll snapping enabled.

What do you think?

GitHub Notification of comment by justingrant
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/4037#issuecomment-511224794 using your GitHub account
Received on Sunday, 14 July 2019 18:26:08 UTC

This archive was generated by hypermail 2.4.0 : Tuesday, 5 July 2022 06:41:50 UTC