w3c / csswg-drafts

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

[css-overflow-5] Scroll button pseudo-elements #10722

Open flackr opened 3 months ago

flackr commented 3 months ago

As part of #9745 I propose adding a pseudo-element which can be created on a scrolling container to provide a button which navigates that scroller. This is a common pattern, typically requiring that developers manually create elements with script to drive these interactions.

Explainer: https://github.com/flackr/carousel/tree/main/scroll-button

E.g. from https://flackr.github.io/carousel/examples/scroll-button/

.scroller {
  overflow: auto;
}
.scroller::scroll-up-button {
  content: "⬆️";
}
.scroller::scroll-down-button {
  content: "⬇️";
}

For a more practical example, see the implicit creation of markers in the carousel demo.

Having these pseudo-elements allows developers to further reduce the amount of extra markup elements they need to add specifically for controls and make their page contents more about the semantics, e.g. a list of content. They can also easily trigger the buttons' presence depending on a state or media query.

Some questions for consideration / resolution:

  1. Should the direction be part of the name or a parameter to a common pseudo-element name, e.g. scroll--button or scroll-button()? My preference is actually for the latter. This may also allow for styling of all scroll-buttons with a single selector.
  2. What is the focus / tree order of these buttons? Naively I would think following the block direction, then inline direction, e.g. up, left, scroller, scroller::before, scroller contents, scroller::after, right, down. That said, there are some designs where the scroll buttons are next to each other in focus order, e.g. the aria apg demo and @argyleink's carousel has them next to each other in focus order despite being visually apart.
  3. Can we use logical directions? Hopefully yes!
  4. How far should clicking one scroll? I think if the scroller has mandatory snap in the scroll axis it should scroll to the next snap area in that axis. Otherwise, I think the most reasonable would be to scroll by a "page" at a time (i.e. the equivalent of the page-up / page-down buttons, typically 85% of the scrollport).
SebastianZ commented 3 months ago

To me, this seems to fit more to HTML. Scroll buttons cause an action (scroll up or down) on an element, which is similar to the popovertarget attribute in relation to elements with the popover attribute.

So we might introduce an attribute like scrolltarget that indicates which element to scroll and another one that determines the direction and maybe the amount like scrollby (with values like e.g. pageup, pagedown, lineup, and linedown) that determines where the element is scrolled to.

Doing so requires more markup, though also gives users more control over it. E.g. they could provide multiple scroll buttons. This also allows for better accessibility by applying appropiate ARIA information. And there wouldn't be any styling constraints.

Sebastian

ydaniv commented 3 months ago

So we might introduce an attribute like scrolltarget that indicates which element to scroll and another one that determines the direction and maybe the amount like scrollby (with values like e.g. pageup, pagedown, lineup, and linedown) that determines where the element is scrolled to.

I like this idea, but I really think it's not mutually exclusive with the OP. IMHO if authors get these buttons created by the UA out of the box and they're stylable, then this covers 80% of use-cases without the need for creating extra markup, and that's a big win. Additionally, being able to specify these manually using custom markup would make this feature highly extensible. So I think both solutions should be considered.

tabatkins commented 2 months ago

Just as a syntax nit, I think this would be better as a functional pseudo ::scroll-button(...). That way you can use ::scroll-button(*) to apply generic styles to your scroll buttons without repetition (in styles or in selectors), and then ::scroll-button(up)/etc for the specific styles (like content to actually trigger the creation of the ones you want).

css-meeting-bot commented 2 months ago

The CSS Working Group just discussed [css-overflow-5] Scroll button pseudo-elements.

The full IRC log of that discussion <bramus> flackr: other major UI component frequent in carousels is having butotns that scroll you through the content
<bramus> … also in scrollers in general sometimes
<bramus> …next/prev page, scroll up/down, …
<bramus> … proposal is to allow devs to create these with a pseudo-element
<bramus> … few options for what that might look lik
<TabAtkins> Big +1 on this, with the only caveat being that we super need this ability captured in a property *as well* which we can put on normal elements (with some suitable restrictions for a11y/usability)
<bramus> … and many open questions
<bramus> … e.g. focus order
<bramus> … seen examples of many different way of setting up these buttons
<florian> q+
<bramus> … want to get some attention on this to figure out if we would be happy to pursue this
<TabAtkins> q+
<SebastianZ> q+
<bramus> … and also some thoughts on specific questions
<astearns> ack florian
<astearns> q+
<bramus> florian: feedback on general idea: on the one hand yes, ppl do add these buttons
<bramus> … proposal goes much broader
<bramus> … for scroll buttons, reminds me of sth that I wanted to do when overlay scrollbars were new
<bramus> … because those scrollbars hide themselves, I wanted to add styles on the element so that users could se ethat it was scrollable
<bramus> … gave up beacuse I was fightnig the UI
<bramus> … similarly the trend is no longer to have scroll up/down buttons … these are useful and users can bring them back (OS setting) or is this a feature devs should bring back?
<bramus> … feel that is is unforutnate tha twe are fighthing back thorugh author space on featuers that UAs have removed
<bramus> flackr: in most cases where authors these, they look nothing like the thing the UA provides
<bramus> … main use case is to recreate native scrollbars
<florian> s/UAs have removed/UAs have removed, then again it is useful
<bramus> … probably are cases that do that, but mostly site specific things
<bramus> florian: fact that they look different is not necessarily diagnostic
<bramus> … I wouldnt have done that if browser kept original UI
<bramus> q+
<astearns> ack TabAtkins
<bramus> TabAtkins: like it, dropped syntax nit suggestion in the issue
<bramus> … the ability to trigger scrolls in whatever direction should be dropped onto a property so that we can put these on real elements too
<bramus> … having pseudos makes sense too
<florian> s/I wouldnt have done that if browser kept original UI/what I used to do back in the day also looked very different from the removed browser UI, I wouldnt have done that if browser kept original UI
<bramus> … figuring out restrictions is a little bit more complicated on those elements, so having only pseudos is fine too
<bramus> flackr: can do this with invokeaction on buttons
<bramus> TabAtkins: sounds reasonable
<astearns> ack SebastianZ
<bramus> SebastianZ: also am reminded of the popover approach
<bramus> … fits more to HTML so that we could introduce HTML attrs that would trigger scroll and then those elements could be style in any way
<bramus> astearns: want to address q3: absolutely
<bramus> … should design so authors can use scroll-start and scroll-end
<astearns> ack astearns
<astearns> ack bramus
<TabAtkins> bramus: Addressing lforian's remark
<TabAtkins> bramus: where he wanted to recreate classic scrollobars, think that's part of another discussion we already have an issue for
<florian> q+
<TabAtkins> bramus: where authors want control over overlay vs classic scrollbars
<TabAtkins> bramus: so maybe something to discuss in that issue
<argyle> hehe, looks like scroll buttons https://usercontent.irccloud-cdn.com/file/08ng5J3C/CSSWG%20zoom%20screenshot
<astearns> ack florian
<TabAtkins> florian: I wasn't so much pointing out that authors want to recreate classic scrollbars, but rather react to scrollbars being less useful as time goes by
<bramus> fantasai: i understand the desire to create these buttons using css
<bramus> … proposal is probably way too ??
<astearns> s/??/simplistic/
<bramus> … how much are you going to scroll by? fragment? page? part of page? section? next scroll marker?
<bramus> … lot of different amounts
<bramus> … q about relation to each other and what order to they appear compared to other pseudos?
<bramus> … lot of option questions
<TabAtkins> It's more than two, fwiw
<bramus> … proposal for 2 pseudos with page-up/down is a bit too simple to addres sproblem space
<bramus> … dont have a good ?? do we want to make this more complicated now or? – dont know what makes sens here
<bramus> … but see a lot of variation of what users want to do and think we need to capture those needs
<joshtumath> s/??/solution
<bramus> flackr: did mention everything you mentioned as a list of open questions
<bramus> … definitely undespecified at this moment
<bramus> … q is not to resolve, but for me to go formulate anwsers to all those questions and then take it back
<bramus> astearns: I suggest yes: work on the questions and need to figure out the details
<bramus> florian: do think it is worth exploring this
<bramus> … also UAs, make scrollbars useful please
<bramus> astearns: we not only need the questions
<bramus> … we need the group of usecases that we are trying to solve
<bramus> … maybe a group of usecases that is out of scope
<florian> s/it is worth exploring this/it is worth exploring this, authors will do this anyway, and it'll be more robust if we provide features in that space that help
<bramus> … discussing things in terms of what the author wants to do
<bramus> flackr: excellent feedback
<bramus> astearns: so we take this back?
yisibl commented 2 months ago

I thought of a similar syntax improvement to that proposed by tab a while back.

But there are some subtle differences:

  1. ::scroll-button() It can select all scroll buttons without *.
  2. Don't use up/down, change it to: ::scroll-button(prev) and ::scroll-button(next)
tabatkins commented 2 months ago

Sure, whether we spell the "select all" case as nothing or * doesn't matter. I think we have a bit more precedent on * for this sort of thing, but I could be wrong.

For the keywords, note that you can scroll in multiple directions; there will be more than two keywords. I expect the set to be up/down/left/right/block-start/block-end/inline-start/inline-end, and having prev and next additionally with the behavior of "whichever axis is scrollable, or block if they both are" sounds nice. (Or maybe "whichever axis has more scrollable length, so a horizontal scroller can have a little bit of vertical overflow without changing the button axis unexpectedly.)

yisibl commented 2 months ago

Sure, whether we spell the "select all" case as nothing or doesn't matter. I think we have a bit more precedent on for this sort of thing, but I could be wrong.

My main concern was that * would lead authors to believe that this function supports CSS selectors.

In addition, can we support scrolling to the scrollbar start and end position here? That is, the first and the last page of the carousel.

flackr commented 2 months ago

Just an update, to list proposed answers to the questions in the OP as something to try to resolve on, I propose the following:

  1. The pseudo-element would be ::scroll-button(<direction>) where direction is up | down | left | right | block-start | block-end | inline-start | inline-end | prev | next. prev | next map to the start / end in the axis having more scrollable length, with a preference to the block axis in the case of ties.
  2. All buttons appear together before the scrolling element but after scroll-marker-group: before in focus order. They are ordered by block-start, inline-start, block-end, inline-end in order.
  3. Logical directions are a core part of the <direction> definition, see points 1 and 2.
  4. They scroll by one "page" of scroll distance (e.g. similar to page up / down keys on the keyboard), which in most UA's is 85% of the scrollport size in the relevant axis but are adjusted by scroll-padding.
johannesodland commented 2 months ago

4. They scroll by one "page" of scroll distance (e.g. similar to page up / down keys on the keyboard), which in most UA's is 85% of the scrollport size in the relevant axis but are adjusted by scroll-padding.

Could it be configurable whether it scrolls one "page" or one snap point/area? I think there are use-cases for both.

Also, when scrolling a fixed amount like 85% with scroll-snapping, an element that was partly obscured before scrolling can end up being partly scrolled out on the other side without ever being fully visible. This is especially frustrating when scrolling in the inline direction, as text can be cropped across lines, making it unreadable. In these cases, we've added code to ensure that only fully visible elements is scrolled out. Would it be possible to address this issue somehow?

hvanops commented 1 month ago

@drewstewartdesigns We talked about focus order and tabbing through carousel content just the other day (question 2 in the original issue). What do you think about Rob's proposal above? Is this how you would expect this to work?

flackr commented 1 month ago
  1. They scroll by one "page" of scroll distance (e.g. similar to page up / down keys on the keyboard), which in most UA's is 85% of the scrollport size in the relevant axis but are adjusted by scroll-padding.

Could it be configurable whether it scrolls one "page" or one snap point/area? I think there are use-cases for both.

Also, when scrolling a fixed amount like 85% with scroll-snapping, an element that was partly obscured before scrolling can end up being partly scrolled out on the other side without ever being fully visible. This is especially frustrating when scrolling in the inline direction, as text can be cropped across lines, making it unreadable. In these cases, we've added code to ensure that only fully visible elements is scrolled out. Would it be possible to address this issue somehow?

Do you have an example? The way that we avoid this issue for carousel experiences is by ensuring that we have appropriate snap areas. I.e. we will target scrolling 85% but given scroll-snap-type: x mandatory it will force it to align to the nearest snap area. I think that defining snap areas would be the recommended way to avoid the scroll resting between lines.

johannesodland commented 1 month ago

Do you have an example? The way that we avoid this issue for carousel experiences is by ensuring that we have appropriate snap areas. I.e. we will target scrolling 85% but given scroll-snap-type: x mandatory it will force it to align to the nearest snap area. I think that defining snap areas would be the recommended way to avoid the scroll resting between lines.

I made a quick example here: https://codepen.io/johannesodland/pen/WNqmoYy

Before scrolling: the 3rd item is partially visible on the right side.

image

After scrolling 85%: it snaps to item 4, leaving item 3 partially visible on the left side.

image
flackr commented 1 month ago

I made a quick example here: https://codepen.io/johannesodland/pen/WNqmoYy

Thanks @johannesodland! I think this is a more general problem with scroll-snap. I filed #10914 to work out how we can make this work as expected (i.e. not skipping over content).

johannesodland commented 1 month ago

Thanks @johannesodland! I think this is a more general problem with scroll-snap. I filed #10914 to work out how we can make this work as expected (i.e. not skipping over content).

You're right @flackr. Fixing this in scroll-snap seems right. Thanks for filing 🙏

It would still be good to be able to scroll snap-area by snap-area, and not page by page though. There are many use-cases for going item by item, i.e. when the snapped item is styled in a special way either through ::snapped or scroll-driven animations.

css-meeting-bot commented 1 month ago

The CSS Working Group just discussed [css-overflow-5] Scroll button pseudo-elements.

The full IRC log of that discussion <TabAtkins> flackr: scroll buttons are conceptually simialr to scroll markers
<TabAtkins> flackr: they are focusable, they hang off the scroll container
<TabAtkins> flackr: and they scroll that element in the indicated direction, as specified by their selector
<TabAtkins> flackr: here i used ::scroll-down-button, but we have syntax alternatives like ::scroll-button(down), this would better let authors specify logical or physical directions, dpeneding on which is appropraite
<ntim> WebKit does want to move away from the PseudoElement class that extends Element
<flackr> https://flackr.github.io/carousel/examples/scroll-button/
<TabAtkins> flackr: so i have a demo built on the polyfill - you also saw them in the Canary live demo
<TabAtkins> flackr: Here's a terms of service agreement or something, page down buttons to go down
<ntim> WebKit only uses that for ::before / ::after. The other pseudos that generate boxes are hooked to render tree building
<TabAtkins> flackr: they should implicitly become inactive when you can't scroll further
<TabAtkins> flackr: and they scroll equivalent to one page, like pressing PgDn
<TabAtkins> smfr: is that the equivalent of a smooth programmatic scroll
<bkardell_> q+
<TabAtkins> TabAtkins: I assume it's basically a PgDn press (possibly in other directions)
<bkardell_> q-
<TabAtkins> smaug: maybe a little tricky, maybe not scrolling a full view of height
<TabAtkins> flackr: my understanding is most browsers scroll 85% of the optimal viewing region of the scroller
<TabAtkins> flackr: so you can still see osme of the previous content
<TabAtkins> flackr: of course, with snap areas it'll align as necessary
<TabAtkins> dbaron: I think some may avoid letting the overlap get too big relative to the default font size, you don't want too many lines repeated
<TabAtkins> smfr: so this is independent from carousels, right? basically a generic "fake scroller" control
<TabAtkins> flackr: yes
<TabAtkins> smfr: and you could have one for the root scroller?
<TabAtkins> flackr: yes
<TabAtkins> dbaron: is it problematic for pseudos to be focusable?
<TabAtkins> flackr: i don't think so
<smfr> q+
<flackr> TabAtkins: we presumably want to make psuedos focusable
<flackr> TabAtkins: i hope it's fine
<TabAtkins> dbaron: I think there's a bunch of things taht assume the curently focused thing is an Element
<TabAtkins> flackr: my thinking is that .activeElement
<jarhar> q?
<TabAtkins> dbaron: that's one of the pieces, yes
<TabAtkins> flackr: it'd give you an actual element, in the case of these buttons its the scroll container
<TabAtkins> flackr: this is similar to having focus in a shadow dom, the host element is the activeElement
<TabAtkins> dbaron: that seems like a reasonable model
<TabAtkins> dbaron: it does need to define tab order and such
<TabAtkins> bkardell_: what's the role?
<TabAtkins> flackr: depends on the pseudo, but needs to be well-defined for each.
<TabAtkins> flackr: for scroll buttons, presumably a button
<TabAtkins> flackr: i definitely want feedback on things like "what is the focus order"
<TabAtkins> flackr: i think general guidance is buttons for navigating should be together in a group, so they hit the buttons, then into the contents
<TabAtkins> bkardell_: right now scrollers don't have focus behavior, right? you focus the area.
<TabAtkins> ??: it depends!
<TabAtkins> flackr: notaby this is not reproducing the scrollbar, it's adding new scrolling affordances
<TabAtkins> hdv: is there a precedent for gencontent to have their own roles
<flackr> TabAtkins: there hasn't been yet as so far they haven't been given focusability
<smfr> q-
css-meeting-bot commented 1 month ago

The CSS Working Group just discussed [css-overflow-5] Scroll button pseudo-elements, and agreed to the following:

The full IRC log of that discussion <TabAtkins> flackr: the ::scroll-button pseudos let authors easily add buttons scrolling partiuclar directions to a scroll container
<TabAtkins> flackr: last time the main thing tha tprevented us from resolving was a lack of clarity on how they would work
<TabAtkins> flackr: i have a specific list of answer to the open questions in my comment
<TabAtkins> flackr: basically, ::scroll-button(<direction>) syntax, taking logical or physical directions
<TabAtkins> flackr: the buttons come before the scrolling contents in focus order, all together
<TabAtkins> flackr: they scroll one "page", as determined by the UA similar to PgDn, in the relevant direction
<TabAtkins> flackr: I have opened a separate issue specifically to talk about the focus order of th epseudos with respect to each other
<lea> q?
<lea> q+
<TabAtkins> TabAtkins: I was gonna ask about that, happy to have it in a separate issue
<TabAtkins> lea: this seems reasanable. could we have a non-parenthetical version so you can style all of them the same way without enumerating them?
<TabAtkins> fantasai: that makes sense, but I'd keep the parens and let it be empty
<TabAtkins> lea: why?
<TabAtkins> fantasai: it's more like a universal selector
<TabAtkins> fantasai: we have other patterns similar to this
<TabAtkins> lea: we have precedent for un-paren'd pseudo-classes
<TabAtkins> fantasai: yeah, but pseudo-elements don't have that precedent. VT pseudos, for instance.
<TabAtkins> lea: Okay, no strong opinion.
<lea> I think `::scroll-button` is cleaner than `::scroll-button()` but not a hill I'd die on
<TabAtkins> flackr: proposed resolution, add ::scroll-button() pseudo-elements to Overflow 5, as describe din the issue
<TabAtkins> RESOLVED: add ::scroll-button() pseudo-elements to Overflow 5, as describe din the issue