w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.49k stars 660 forks source link

[css-overflow][css-overflow-4][proposal] Define the scrollable area of an element #3428

Open andyearnshaw opened 5 years ago

andyearnshaw commented 5 years ago

https://drafts.csswg.org/css-scrollbars-1/

Following on from my previous proposal of scrolling elements that have no "natural" overflow (which this doesn't depend on but would be a smart addition for that), there are elements that have fixed, non-scrollable areas. You can sometimes solve this problem by using other elements to separate the scrollable area. However, sometimes they may converge on both axis at a specific area, but outside of that area the content is still scrollable on one of the axis. That's not a great way of articulating the problem, I suppose, but here is an image that might help:

In this example, the green area represents horizontally-scrollable content and the red area represents vertically-scrollable content. Because of how scrollbars automatically take up 100% of the available height or width of an element, you can't limit them to the area that will actually change if you move those bars.

The idea I had for this was just to define a new property, e.g. scroll-area that allows you to set the rectangle for the intersecting scrollable area, so that the scrollbars don't overlap non-scrollable areas on their respective axis.

:host {
    scroll-area: inset(10%, 0, 0, 10%);
}
jonjohnjohnson commented 5 years ago

Maybe someone from the microsoft team could way in on what went into the reasoning for their -ms-scroll-limit property (description)? Seems like there could be crossover here. This property doesn't change scrollbar track placement, but it does effectively change the start/stop edges of the scrollbar thumbnail.

Though, more than limiting a scrollable area within a scroll container, I've often found myself just wanting to limit the placement of scrollbars within a scroll container, "pulling" the scrollbar tracks placement in from the containers edges, to leave room for many of these visually non scrolling areas, even if only sometimes non scrolling, like what google has called "hidey bars" that move in and out of view with scrolling direction. So fixed/sticky headers/footers/sidebars are never obfuscated by the scrollbar/track.

Since we have scrollbar-width, what about scrollbar-inset/scrollbar-insetstaking physical/logical offset values?

This seems to quite literally relate to the rhetoric in scroll-snap for "Optimal Viewing Region" from scroll-padding https://drafts.csswg.org/css-scroll-snap-1/#optimal-viewing-region?

So just allow overlay scrollbars to key off scroll-padding, even/especially if auto? Or maybe a scrollbar-padding property?

jonjohnjohnson commented 5 years ago

Furthermore, today, we have a much more complex state of scroll containers interacting with the transform/perspective/sticky features, where we don't need as much javascript to handle interesting scroll interactions writing to the dom on scroll events at runtime, but to truly take advantage of these features, we often need to manipulate scroll containers in unconventional ways that scrollbars currently don't jive with.

Take the interface linked below for example. A pure HTML/CSS "swipeview" with effects that allow parallaxing/revealing/covering horizontally between pages. Works well in blink/webkit/gecko, especially in touch env with overlay scrollbars. But the scroll container needs to be outset far from the viewport, then "clipped" back into match it for these effects and then the scrollbar track is far from useful.

Click the blue header to cycle different "swipeview" styles, and scroll horizontally across the main content to see their behaviors.

If you change the --bottomScrollOffset on the .pager element to 0px you'll see the horizontal scrollbar track come into view and once scrolling, you'll notice the ludicrous behavior it offers when needing to manipulate the scroll container in this way.

If we had a way to inset the scrollbar/track, this example could easily be remedied by a declaration of scrollbar-inset: 0 var(--pageWidth)?

@upsuper After working on geckos scrollbar-width/scrollbar-color features what would you think about insetting scrollbars from the edge of their scroll containers? Or at least inset in the direction of their scrolling axis?

upsuper commented 5 years ago

@upsuper After working on geckos scrollbar-width/scrollbar-color features what would you think about insetting scrollbars from the edge of their scroll containers? Or at least inset in the direction of their scrolling axis?

I don't think they have much similarity. Controlling scrollable area is a totally different topic than styling the scrollbar. That may be much harder given that there have been many scrolling-related features added, and browsers have invested a lot on optimizing scrolling.

I don't really understand the usecase to be honest...

jonjohnjohnson commented 5 years ago

@upsuper I think the key distinction is wanting scrollbars to match the "visually" scrollable part of a scroll container, when parts of the container could be covered by fixed or sticky elements from its flow, or even an element outside that partially covers the scroll container, like "hidey bars" that many native mobile apps have, think the twitter or reddit apps.

So put simply, a vertical scrollbar always runs the full height of a scroll container. What if we had a property that could set the the scrollbar/track in from that top and bottom edge? Say the height of a translucent fixed header that is 50px tall? Something like scrollbar-inset: 50px 0?

I know some browsers even have a few heuristics in place to analyze what "page down/up" means when fixed elements cover some of the scrollport, and an initial value of auto could possibly lend property to be used alongside those heuristics?

A simple as "I'd like this scrollbar to not run whole length of my scroll container, and instead leave space for a sometimes animated fixed header and footer so the scrollbar starts and ends alongside those elements and doesn't cover them.

Of course this is all in relation to "overlay" scrollbars, not scrollbars that take up place in the box tree.

PS Did my talk of transform/perspective/sticky not make any sense when reasoning about how they interact with scroll containers and desiring to place a scrollbar in ways it's currently limited? The linked test case showing the scrollbar way off screen?

Also, back around chrome 42 there was a bug from non-zero border radius on scroll containers that made scrolling overflow still visible. This bug afforded something similar to this feature. Here's a gif of it... visibleoverscroll It's just asking for a scrollbar that wouldn't run the full length/edge of the scroll container.

jonjohnjohnson commented 5 years ago

@upsuper In this example, it would be so the scroll container on the right would place its scrollbar the same as on the left, but in a container that visually allows that overflow to be viewed underneath the header.

https://jsfiddle.net/e8aszxrn/

screen recording 2018-12-12 at 09 24 pm

andyearnshaw commented 5 years ago

@jonjohnjohnson thanks for providing more use cases. The one about still being able to see the content as it scrolls "outside" is an interesting one that I hadn't thought of.

@upsuper this is mostly about giving developers more flexibility over the appearance of scrollbars and the behaviour of scroll containers. You may feel that there are workarounds to problems like this, but they always come with tradeoffs. Here's a gif animation of the grid I'm working on at the moment:

scroll area

The grid, as I explained in https://github.com/w3c/csswg-drafts/issues/3397, is highly optimised. It's using custom scrollbars at the moment, but I am hoping to implement native scrollbars if your previous suggestion doesn't cause any issues. The row/column labels are rendered in a separate elements, but all the cells are rendered in a single container. You can see that rows 15, 25 and columns 15, 25 are "frozen", so the cells in those frozen columns do not change when you scroll horizontally, but do change when you scroll vertically (and vice versa for the frozen rows). This means the scroll area is defined by the darker border going across the grid. Our custom scrollbars aren't currently confined to this area, but it's one of the upcoming changes planned. There would be no way to confine native scrollbars to that area without using a separate container for the scrollable area, but this would massively increase complexity in our codebase.

I hope that clarifies the issue better.

jonjohnjohnson commented 5 years ago

@andyearnshaw I think my suggestion and use case is the same as yours, even if in mine it just translucently shows content scrolling underneath what may be a position: sticky placed element in one direction of the scroll or the other. It's attempting to give more freedom to where a scrollbar might be placed alongside what an author doesn't have scrolling through.

The gif I showed is just what I most commonly see as a parallel in native UI scrollbars that wouldn't just have a scrollbar running the full length of their scroll container.

To see a live example of what your gif exhibits see https://codepen.io/SimplyPhy/pen/oEZKZo

jonjohnjohnson commented 5 years ago

@upsuper Maybe this (very dirty and full of magic numbers) demo will help explain? Again, this seems only related to overlay scrollbars. And maybe this could just key straight off the scroll-padding value not needing a new property?

screen recording 2018-12-20 at 11 01 am

Check it out in chrome - http://jsfiddle.net/f01Lsh7y/

jonjohnjohnson commented 5 years ago

@andyearnshaw Do you want to change the title of this issue to something that more clearly communicates the desired feature of "insetting the placement of overlay scrollbars"?

upsuper commented 5 years ago

@jonjohnjohnson As you have mentioned, this example seems to only be useful for overlay scrollbars, for non-overlay, the scrollbar would still need to take the space all the way to the original edge even if we restrict its range, otherwise you would probably have a lot of trouble with the layout. If it needs to reach the edge anyway, I don't really see how this would be useful. Maybe better just use scrollbar-width: none and implement a custom overlay scrollbar would be easier.

andyearnshaw commented 5 years ago

@upsuper what if we suggest that scrollbars should always overlay if this property is defined? ~This is already the behaviour of browsers on Windows if you use the sticky scrolling virtualisation trick you suggested in the other issue, so for that use case it makes absolutely no difference~ (edit: this was incorrect, there was a mistake in the CSS code I wrote for my demo). It may require some additional properties to prevent the scrollbar from obscuring content, though.

Alternatively, it wouldn't necessarily be a bad thing if it did only apply to overlay scrollbars, as it wouldn't create an inconsistent experience for any single user, whereas a custom overlay scrollbar would. The goal here is to keep native scrollbars and avoid changing the actual look and feel of them.

@jonjohnjohnson as I said to @upsuper, this property could potentially force overlaying of scrollbars, in which case that title would be inaccurate. I'm happy to change it if we can pin down the details into something that is acceptable, however.

jonjohnjohnson commented 5 years ago

Ok, then I'd suggest checking out the current state of https://drafts.csswg.org/css-overflow-4/#scollbar-gutter-property to see how your suggestion works in the mix.

andyearnshaw commented 5 years ago

I guess the only part that would change is this, if we were to suggest that inset scrollbars were to become overlay scrollbars:

Whether classic scrollbars or overlay scrollbars are used is UA defined.

I don't think anything else is affected.

jonjohnjohnson commented 5 years ago

@tobiu I think this is also what you were trying to ask about here? https://github.com/w3c/csswg-drafts/issues/2155#issuecomment-411910367

tobiu commented 5 years ago

@jonjohnjohnson yes, definitely related.

tantek commented 4 years ago

As @upsuper noted, and as explicitly clarified in its scope section (https://drafts.csswg.org/css-scrollbars-1/#scope), CSS Scrollbars is purely for styling the controls themselves, not the scrollable area.

Scrollable area and scrollability in general is already defined by and in-scope for CSS Overflow. Am re-labeling this issue accordingly so it’ll get the proper consideration for that spec.

label: css-overflow-4

(Originally published at: https://tantek.com/2020/024/t1/)

jonjohnjohnson commented 3 years ago

@tantek I'm quite confident that @andyearnshaw is requesting ability to style controls, specifically the placement of controls, which is much more to do with the css-scrollbars spec.

I think the "non-scrollable areas" mentioned are just areas where fixed or sticky positioned elements always remain in view of the scrollport.