Skip to content
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

[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 #3349

Closed
jonjohnjohnson opened this issue Nov 27, 2018 · 17 comments

Comments

@jonjohnjohnson
Copy link

jonjohnjohnson commented Nov 27, 2018

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;
}
<scrollport>
  <scrollbox>
    <content>
    </>
  </>
</>

...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...

overscroll-behavior: never

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

Demo of example code - Best in current Firefox Nightly

@jonjohnjohnson
Copy link
Author

jonjohnjohnson commented Nov 27, 2018

@jonjohnjohnson
Copy link
Author

jonjohnjohnson commented Nov 28, 2018

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.

@andersk
Copy link

andersk commented Mar 8, 2019

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

@jonjohnjohnson
Copy link
Author

jonjohnjohnson commented May 14, 2019

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.

@majido
Copy link
Contributor

majido commented May 15, 2019

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.

@jonjohnjohnson
Copy link
Author

jonjohnjohnson commented May 15, 2019

@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.

@jonjohnjohnson
Copy link
Author

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. :/

@chengyin
Copy link

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?

@jonjohnjohnson
Copy link
Author

jonjohnjohnson commented May 15, 2019

@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.

@chengyin
Copy link

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?

@jonjohnjohnson
Copy link
Author

jonjohnjohnson commented May 16, 2019

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.

@jonjohnjohnson jonjohnjohnson changed the title [css-overscroll-behavior] Inhibiting "scroll chaining" from non user scrollable elements? [css-overscroll-behavior] Add support for controlling overscroll relative to user scrollability as well as fully supporting non-boundary-reached scroll chaining, like is already half supported for overflow:hidden elements May 16, 2019
@jonjohnjohnson jonjohnjohnson changed the title [css-overscroll-behavior] Add support for controlling overscroll relative to user scrollability as well as fully supporting non-boundary-reached scroll chaining, like is already half supported for overflow:hidden elements [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 May 17, 2019
@jonjohnjohnson
Copy link
Author

@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.

@chengyin
Copy link

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?

@andersk
Copy link

andersk commented Jun 18, 2019

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.

@jonjohnjohnson
Copy link
Author

jonjohnjohnson commented Jun 18, 2019

@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.

@andersk
Copy link

andersk commented Jun 18, 2019

@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.)

@jonjohnjohnson
Copy link
Author

jonjohnjohnson commented Jun 18, 2019

@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.

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