Csswg-drafts: [css-overscroll-behavior] Control behavior based upon user scrollability and for chaining/bubbling up from elements not being at a scroll boundary, like the supported of overscroll of overflow:hidden elements not at scroll boundary

Created on 27 Nov 2018  Â·  17Comments  Â·  Source: w3c/csswg-drafts

https://drafts.csswg.org/css-overscroll-behavior-1

Consider...

body { height: 110vh; }

.scrollport {
  overflow-y: scroll;
  overscroll-behavior-y: none;
  scrollbar-width: none;
}
.scrollbox {
  margin-bottom: -1px;
}
.scrollbox::after {
  content: '';
  display: block;
  height: 1px;
}
.content {
  position: sticky;
  top: 0;
  bottom: 0;
}

```html





...effectively (inefficiently) creates an element which visually doesn't scroll, yet inhibits scrolling from "chaining" up/outside the element vertically.

I know that `overscroll-behavior` is currently most about reaching previously unreached scroll boundaries and may be a simpler/subset of what was set out for the initial stab at `ms-scroll-chaining`, but when I see...

> Note: This property should provide guarantees that are, at least, as strong as `preventDefault` for preventing both scroll chaining and overscroll. Doing otherwise would cause content authors to use preventDefault instead.

...I wonder if it would be useful to have/specify a simpler (css) way to inhibit scrolling events from certain elements of a ui regardless of scrollability. I know as I develop more native-like web interfaces, I come upon scenarios where I don't have a block that is user scrollable, but would very much like it to not allow scrolling up the document, even if its ancestors participate in scrolling. Especially when chaining in the opposite direction is desired (see touch events start/move based upon direction), `preventDefault` becomes a bit spicier.

I'd imagine it should definitely be separate than just the current `none` or `contain` values when `overflow` set to `auto` more often than not desires scroll chaining.

With values like `always` for `break-after`/`scroll-snap-stop` maybe an initial suggestion makes sense as...
```css
overscroll-behavior: never

...and could then apply to elements that are non-visible/clip overflow?

Demo of example code - Best in current Firefox Nightly

css-overscroll-1

All 17 comments

cc
@majido
@mbrubeck via Pointer Events / touch-action

Furthermore, when a scroll container overflows in one dimension, a none/contain value is honored on the opposing dimensions overscroll-behavior. For example, an element with overflow-x: scroll which overflows horizontally that has overscroll-behavior-y: contain will not, itself, scroll vertically and will also inhibit chaining up vertical scroll events to it's ancestor vertical scroll containers.

And with scrollable elements that are responsive, not always overflowing, you can't always use a preventative touch-action value as a solution. You have to ad a resize observer to analyze overflow and swap between touch-action and overscroll-behavior affects.

I agree. This is important for the modal/overlay case described in the Google article introducing overscroll-behavior.

Just stumbled on a case I figure is worth mentioning here, where it would be real handy to inhibit/allow overscrolling per edge/direction, not just per axis.

The case is a notification drawer that pulls out onto the screen above main view. But uses scrolling/snapping to do so. And inside the drawer is another scroll container where a user can scroll heaps of notifications. With the notification drawer coming into and out view from the top, I'd love to inhibit overscrolling from the top of the inner notification scroller, but allow chaining from its bottom edge, allowing the drawer to be "thrown" out of view from an inner scroller interaction at that bottom edge. For now, a 1px scroll event offset in js is fine, but with more of the web trying to accommodate native-like gesture-rich interfaces, it could be worth putting this in the css side of the web platform.

Per spec - overscroll-behavior applies to all scroll containers even those that don't overflow. In other words it should apply to elements with overflow:auto and overflow: hidden.

Our implementation in Blink has a known bug where it does not do this correctly for 'auto' and 'hidden' scroll containers. But that is an implementation issue. I think Gecko has the same bug.

Overscroll is a behavior that is tightly coupled with scroll chaining and I don't think it makes much sense for it to be exposed to all elements beside scroll containers. Correct me if I am wrong but as far as I can tell the original issue you have raised would be addressed if implementation where correctly honoring the property for 'hidden/auto' values. Adding an overflow: hidden to make your element overflow should not be too problematic.

As for issue of having direction specific overscroll-behavior. That is a separate issue. Can you please file a separate issue for it.

@majido

Correct me if I am wrong but as far as I can tell the original issue you have raised would be addressed if implementation where correctly honoring the property for 'hidden/auto' values.

Hmm, sure, but what if an overflow: hidden scroll container has non-zero overflow?

<scroller>
  <box></box>
</scroller>
scroller {
  overflow: hidden;
  height: 100px;
  overscroll-behavior: contain;
}
box {
  height: 101px;
}

The overscroll behavior controls the permitted boundary default action for a scroll container element when its scrollport reaches the boundary of its scroll box. - https://drafts.csswg.org/css-overscroll-behavior-1/#overscroll-behavior

Are you thinking the example code really should behave in a way where a user performs an upward scroll on the scroller and scroll chaining would be inhibited up the document, but since (unless programmatically scrolling down to boundary) the element would always be 1px off from the bottom scroll boundary, then all of a sudden a users downward scroll would "chain", scrolling an outer scroller?

I guess, I'm just not totally sold on the language/behavior being solely about boundaries here and would like a more full fledged scroll event chaining feature that is not limited to, encompasses boundaries.

_UPDATE_

I see this last code example attempting a real hacky direction specific overscroll-behavior like I brought up previously.

And actually, regarding overflow:auto, I think there are ample cases of responsive UIs where an authors desire would be to contain ONLY IF the scroll container has overflow, not always contain because it happens to always be a scroll container.

So I guess I'm not sure I support the blanket statement of scroll containers in the current version of the spec. :/

And actually, regarding overflow:auto, I think there are ample cases of responsive UIs where an authors desire would be to contain ONLY IF the scroll container has overflow, not always contain because it happens to always be a scroll container.

Are there more cases here than the cases that require consistent behavior? Or are you suggesting making this behavior configurable?

I've not been able to use this rule due to the inconsistent behavior in this ticket. In our application, I cannot think of any case that I would _prefer_ to contain the scroll conditionally. There are cases either could work, but some usages would only work if scrolling chaining is universally inhibited regardless the scrollability.

Just take Google's Chatbox demo, the rule only works if the Chatbox is not scrollable. To me this clearly is a bug caused by the inconsistent behavior. Or is this not an intended usage of the rule?

@chengyin I am suggesting more options, yes, a *more configurable form than is currently offered.

Regarding...

I think there are ample cases of responsive UIs where an authors desire would be to contain ONLY IF the scroll container has overflow, not always contain because it happens to always be a scroll container.

<aside>...</aside>
<main></main>
body {
  display: flex;
  align-items: stretch;
  min-height: 100vh;
}
main { flex: 1 1 auto; }
aside {
  position: sticky;
  top: 0;
  width: 15rem;
  overflow-y: auto;
  overscroll-behavior-y: contain;
}

This might be too simplified, but I've seen many similar UIs where if the content of the sidebar does not happen to create overflow the author would like scrolling atop the sidebar to scroll the body/main. BUT if the content of the sidebar does create overflow, then the author'd rather not have chaining from the scroll boundaries of this user scrollable sidebar. I see native touch interfaces exhibit this logic often as well.

So I guess my initial proposal of a never value for overscroll-behavior on all scroll containers, with maybe contain/none values only affecting scroll containers that have "user scrollable" overflow, would provide more options for authors is all.

_Also_

but some usages would only work if scrolling chaining is universally inhibited regardless the scrollability

I completely agree, hence the title of this issue. I want the *bug(s) that @majido described to be ironed out and for your case and many of mine to be solved. Just noting intricacies that should probably be taken into account for this property to be as useful as possible.

I am not against making it configurable but I found the example here interesting since this exactly is my use case. Our requirement turns out to be the opposite though. We see sidebar and main content as separate interactive areas. Scrolling in sidebar should not affect the main content in any state. This got me curious in what cases would one want chaining?

If two completely independent scrollers sit side by side, I’ve simply not nested one in the other. This is how I understand your use case. No scroll chaining behavior is even needed if not nested. @chengyin, if this doesn't work for you, could you explain why?

However, if conditionally one might want scrolling to chain, then nesting is a great way to not have to retarget scroll events with js between two independent scrollers.

In my example, if sometimes the height of an environment/browser is tall enough that the aside would never overflow/scroll itself, then it can be good UX to afford scrolling over that area to affect the main (outer) scroller. This is how users have historically understood scrolling from atop fixed positioned headers or sidebars. So from a rwd perspective, enabling scroll chain inhibition based upon the aside actually overflowing seems like an often clean and desirable solution.

@chengyin Here is the current chrome *bug in chromes own settings view. And I think this is sometimes a desired behavior. When there is no user scrollable overflow on a scroll container, you might not want to inhibit scroll chaining.
Screen Recording 2019-06-10 at 08 13 PM
This could feel strange if when the screen is large enough, scrolling with your mouse in the lower left area would move the main settings scroller, but not when your mouse is in the upper left, while the sidenav isn't actually scrollable.

Similar to how a scroll container needs to have user scrollable overflow to participate in the "sequential focus navigation order", I think it's valuable to offer configuration that can key off scrollability.

Hey Jon, thank you for the example. In this particular design, the behavior there is no visual boundary between the sidebar and content, so I can see the behavior could be desired. If overscroll-behavior is on #left instead, and sidebar never trigger content scroll, would you consider that a bug?

Also, where are we at the discussion? Are we trying to decide what behaviors should overscroll-behavior support? Or are we trying to decide what is the behavior for overscroll-behavior: contain?

If two completely independent scrollers sit side by side, I’ve simply not nested one in the other.

That doesn’t work for the modal dialog case, where we want to inhibit scrolling of the entire page (regardless of whether something in the modal can scroll or not), and “not nesting the dialog inside the entire page” is not a thing.

@andersk yup, it's a different case, and is why I changed the title of this to address more configuration options of this property. And above, @majido already addressed the current state of blinks bug that resolves the case you describe.

"Not nesting the dialog inside the entire page” is not a thing.

Though I wouldn't always recommend it, it can be a thing. You just sacrifice the root scroller niceties and simply have two independent sibling scrollers that are fixpos/abspos inside the body element. One scroller for the main content, the other scroller, above, for the modal content.

Also, as far as blink goes, a user scrollable fixed scroller doesn't participate in the root scrollers chain, so overscroll-behavior has no effect. You couldn't enable scroll chaining if you tried.

@jonjohnjohnson That doesn’t match my observation: in both Blink and Gecko, scrolling propagates up to the root scroller if the fixed modal doesn’t have enough content to be scrollable on its own. (Test case.)

@andersk, again, @majido addressed that as a bug in both blink and gecko. It's in his first comment in this thread. The spec already supports your case. Feel free to file/comment on bugs in implementations that don't follow the spec.

I'm closing this as far as the majority of the concerns in this thread are already supported by the spec.

I'll file separate issues for direction specific overscroll and an intentional overscroll option that keys off of user scrollability, which is similar to the bug this original filing thought was the spec defined behavior.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

CJKu picture CJKu  Â·  4Comments

schenney-chromium picture schenney-chromium  Â·  3Comments

svgeesus picture svgeesus  Â·  3Comments

nigelmegitt picture nigelmegitt  Â·  4Comments

LeaVerou picture LeaVerou  Â·  3Comments