w3c / csswg-drafts

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

[css-overflow-5] Scroll-markers #10720

Open flackr opened 3 months ago

flackr commented 3 months ago

This issue is to introduce scroll-markers (explainer), which is the main new feature proposed in #9745 for declarative creation of dynamic navigable scrolling user interfaces.

Anchor links to elements on the same page are effectively scroll markers, e.g. <a href="#section1">Section 1</a> is a scroll marker for section 1. In the css-overflow-5 spec, I propose a mechanism for automatic creation of scroll markers from content with pseudo-elements, as well as implicit grouping of and scroll tracking within groups of scroll markers.

Pseudo-elements

::scroll-marker-group

A scroll container can establish a pseudo-element for containing ::scroll-marker pseudo-elements by setting the scroll-marker-group property to one of before or after signifying the order of the ::scroll-marker-group in the tree, either before or after the scroll container. The ::scroll-marker-group pseudo-element can be styled as the author wishes.

In order to ensure that placing ::scroll-marker pseudo-elements into the ::scroll-marker-group does not create cycles (e.g. change the layout in a way that affects the number of ::scroll-marker pseudo-elements), the UA stylesheet applies contain: size to the group.

E.g.

.scroller {
  scroll-marker-group: after;
}
.scroller::scroll-marker-group {
  border: 2px solid black;
  padding: 8px;
  height: 30px;
}

::scroll-marker

The author can then add a ::scroll-marker style with a non-empty content attribute to any number of elements in the scrolling container to which navigation markers should be created. E.g.

/* Creates circular scroll markers pointing to each section. */
section::scroll-marker {
  content: ' ';
  border: 2px solid gray;
  border-radius: 50%;
}

Combined with #10715, authors can create these dynamically for each generated fragment allowing the creation of automatically paginated content.

Groups of scroll markers

A group of scroll markers is established automatically by ::scroll-marker-group, and can be established manually for <a> elements by placing them into a containing element with the focusgroup attribute. E.g. the following demonstrates an inline table of contents establishing a scroll marker group:

<ol focusgroup>
  <li><a href="#introduction">Introduction</a></li>
  <li><a href="#background">Background</a></li>
  ...
  <li><a href="#conclusion">Conclusion</a></li>
</ol>

Within each group, an active marker is determined based on the scroll position and can be styled by the developer using the :checked pseudo-class, e.g.

a:checked {
  font-weight: bold;
}

In addition to being explicitly focused, whenever a scroll marker becomes active by scrolling, it sets the last-focused element of its focusgroup to itself. In combination with the guaranteed tab stop of focusgroups, this means that tabbing into a group of markers with tabindex -1 will focus the currently active marker. ::scroll-marker pseudo-elements implicitly have a tabindex of -1 establishing this behavior.

kizu commented 3 months ago

I really like the idea of the scroll markers, although I am a bit wary of the dynamically created interactive elements, I'll copy the comment I did in the related thread from last December:

I don't like the idea of having the interactive elements created as pseudo-elements, or a need to manually place elements and then somehow associate them with the fragments etc.

But what if (wild idea incoming)… an ability to declare a <template> which would be used for every fragment? Maybe even with some built-in slot content that could be used, like for the markers, “page count” etc.

(there was a bit more to the discussion in the thread, I won't copy it fully)

However, regardless of how the actual dynamic scroll-markers will be implemented (maybe there is a way for the browsers to expose them in an accessible and extensible way), I think there is one thing about this proposal that we could implement right now — the idea of a :checked pseudo-class for the current marker:

Within each group, an active marker is determined based on the scroll position and can be styled by the developer using the :checked pseudo-class, e.g.

This pattern is something that gets re-implemented over and over again, in our App I remember it appearing in different forms at least three times in the last 2 months.

I did also successfully implement this pattern with scroll-driven animations in the past: https://kizu.dev/scroll-driven-animations/#table-ofcontents-with-highlighted-current-sections — so it is already possible today (in Chrome) with just CSS. But it is very awkward to implement even with the scroll-driven animations, so having a native feature like this could be very useful.

Thus, my proposal: split the :current state as something that could be the least questionable to implement (this could be a quick win), and continue discussing the dynamic scroll-markers themselves separately (as in my opinion there is much more to them that we need to think about, and I don't want them to stall what the :checked could bring).

css-meeting-bot commented 3 months ago

The CSS Working Group just discussed [css-overflow-5] Scroll-markers.

The full IRC log of that discussion <bramus> flackr: we previously discussed the issue of a broad set of ways to make it easy for devs to author carousels with css
<bramus> … this is one of the features of that
<bramus> … goals is to have a simple way for devs to create nav markers. typically dots in carousels
<bramus> … but also useful for TOCs
<bramus> … or tabbing mechanism when you have a scrollable tab container
<bramus> … have written up a spec in css-overflow-5 as prevously resolved.
<bramus> … idea is that scroll markers behave as anchor links
<bramus> … but they have one main additional component is that you can trck whichone is the active one
<bramus> … so for a group there is an extra style that applies to the “current one”
<bramus> … you can also create the groups as pseudos automatically for pagination scenarios based on fragmentation
<bramus> … issue is here to get attention on this and to bring everhyone up to speed
<bramus> … how this could work with regular elements ??? by having groups of links
<bramus> … is focusgroup the right thing or should wwe have a group name (for a later discussion)
<kizu> q+
<bramus> … already have 1 proposal in the spec and want concensus on the direction
<astearns> ack kizu
<bramus> kizu: left a comment, like the idea
<bramus> … there is a lot of things with related issues
<bramus> … one aspect that i tink could be quick win
<bramus> … to split off highlighting of currently applied marker
<TabAtkins> +1 from me, I'm v happy with this. Still some work to do but I think the current approach and syntax is good
<bramus> … for all TOCs this would be useful
<bramus> … had a lot of need for this recently
<bramus> … TOC, tab list, etc
<bramus> … need JS for that now with IO
<bramus> … can also use SDA but thats a hack
<bramus> … this one thing could be useful to split off
<bramus> flackr: hadnt got chance to respond on issue yet
<bramus> … in order to do auto selection it requires to have a grouping mechanism
<bramus> … because active item needs to know which group it is in
<bramus> … so that TOC doenst interfere with set of inline links
<bramus> … I dont think that auto creation adds a whole bunch of complexity
<bramus> … if we just focused on active state, then we might forget to allow auto creation
<bramus> … you als mentioned you would like template instantiation
<bramus> … feels like a good thing for filling in content for pseudo elements generally
<bramus> … sth that could be augmented later for markers (and ::before, ::after, etc)
<bramus> … its not mutually exclusive to have pseudos for this now
<bramus> … having whole thing in spec also doesnt mean vendor has to implement the whole thing
<florian> q+
<bramus> … do see value in having it all specced out now
<florian> q+ astearns
<florian> q- later
<astearns> ack florian
<bramus> florian: way back in the day opera had tried (for frag use case) to have these markers be auto generated or to have an API for devs to suppress that
<bramus> … AFAI remember there was no psuedo element
<bramus> … not saying we shoudl be doing antyhing like this
<florian> https://www.wiumlie.no/2011/reader/
<bramus> … want to raise awareness about that effort
<bramus> … could give some ideas
<fantasai> -> https://drafts.csswg.org/css-overflow-5/
<bramus> flackr: wasnt aware of that specific case but have feedback that authors dont want to write JS to create stuff like this
<bramus> … do see value in purely declarative setup for this
<bramus> florian: absolutely
<bramus> … link I shared is either fully automatic or JS
<bramus> … JS override might be nice
<bramus> … for context: broader thing back then was to be able to opt in to pagination as an alternative to scrolling
<bramus> … they wanted that feature in that context
<astearns> ack astearns
<bramus> … again, purely sharing for awareness reasons and backhistory
<bramus> astearns: where are you with other bits of the process?
<bramus> … implementing things? sending intents? is this getting TAG review?
<bramus> flackr: of course it will go through TAG and what not
<bramus> … have a partial experimental thing in Chrome
<bramus> … to prove that we can have focusable pseudos
<bramus> … and that it supports these use cases
<bramus> … should add a few links with concrete demos in the issue
<bramus> … thats where we are at
<bramus> … want to get consensus on specific shape to push this forward
<bramus> … make sure everyone is happy
<bramus> astearns: other qs or comments?
<astearns> ack fantasai
<bramus> fantasai: great ? to to work on. spec needs a bit more explanation.
<bramus> … makes sense to have ability to have an existing anchor to be both a scroll marker and also having the pseudo
<bramus> … spec doesnt do a good job of pullin gthis together in coheren model
<bramus> … (editorial criticism)
<bramus> … makes sense to pursue this direction
<bramus> … with a little bit of work on the editorial side this would be a reasonable FPWD
<bramus> astearns: cool
<bramus> … what else do you want for this issue, rob?
<bramus> flackr: please open indiv issues on the proposal
<bramus> … will make work of editiroal work
<bramus> astearns: so you dont need resolutions?
<bramus> flackr: we alsready have a resolution to work on this (back february)
yisibl commented 3 months ago

Is the content property required? I don't think the content property is necessary if you don't need to generate text.

flackr commented 2 months ago

Is the content property required? I don't think the content property is necessary if you don't need to generate text.

This is how you tell which elements generate scroll-markers. The initial content value of none for the ::scroll-marker pseudo-element is how we know not to generate scroll-markers for every other element.

This is the same model as ::before and ::after, and given the scroll-marker should show something, using the content property to activate it seems like a good pattern to follow making it obvious to the author if they show an empty string they should make it visible via styles.

css-meeting-bot commented 2 months ago

The CSS Working Group just discussed [css-overflow-5] Scroll-markers.

The full IRC log of that discussion <TabAtkins> flackr: you can imagine this like a ToC for a scrolalble element
<TabAtkins> flackr: in my example, one way to do it is create a set of anchor links to your content
<TabAtkins> flackr: I'm proposing you add `focusgroup` to get the input semantics you expect - can arrow between them, only one is active at a time
<TabAtkins> flackr: And the browser has some tracking to update which one is "active" at a time
<TabAtkins> flackr: if your page only contains top-level sematnic items - a list of items - you can create pseudo-elements for these
<TabAtkins> flackr: this is crucial for autoamtic pagination, like columns, so you can have one marker per page, not one per item
<flackr> https://github.com/flackr/carousel
<TabAtkins> flackr: here's a simple live example, three sections, declared that each creates a scrol lmarker, and they've been flowed into the scroll marker group on the left
<hdv> q+
<TabAtkins> flackr: [showing source] roughly speaking, you add a pseudo-element for each thing that needs a marker, and a scoll-marker-group pseudo is automatically created to hold them
<TabAtkins> hdv: what are the a11y semantics of something that becomes a scroll marker?
<bkardell_> q+
<TabAtkins> flackr: shoudl be whatever makes the most sense for these use-cases. given that we upgrade links, i assume it woudl ahve the same sematnics as an anchor link
<bkardell_> q-
<Patrick_H_Lauke> link with aria-current="true"...
<hdv> ack me
<TabAtkins> TabAtkins: and note that in this example it's *generating* fresh anchor links, they can be whatever. if reusing elements on the page, they have to be links already
<TabAtkins> flackr: this example reuses existing links. The ToC links are in a focusgroup, and we track sc roll progress to indicate which is active
<bkardell_> q+
<TabAtkins> flackr: I also have a separate scroll marker group on the right to track the top-level sections.
<TabAtkins> flackr: each group has its own "current" marker
<TabAtkins> flackr: inline links, not in a focus group, dont' get considered in this, they're never marked as "current"
<flackr> https://drafts.csswg.org/css-overflow-5/
<TabAtkins> flackr: This is the most mature of these specs, it's currently in the CSS Overflow 5 spec
<flackr> https://codepen.io/flackr/pen/MWMLPpP
<TabAtkins> flackr: what i've shown so far is a polyfill, but we have an impl in Chrome Canary with experimental web paltform features turned on
<TabAtkins> flackr: the only content on this page is a bunch of items. they're automatically grouped into pages, with scroll markers for each page, and next/prev buttons, and it's all automatic from CSS
<TabAtkins> flackr: any questions about scroll markers or move on?
<TabAtkins> bkardell_: This is dependent on the focusgroup attribute? what's the progress on that right now?
<TabAtkins> flackr: to make a scroll marker group from link elements, that's dependent on focusgroup
<TabAtkins> flackr: we implicitly have the semantics for the pseudo-elements, but it doesn't depend on the attribute
<TabAtkins> bkardell_: does the implementation support focusgroup?
<jarhar> q?
<TabAtkins> flackr: the pseudo-element impl has an implementation of focusgroup semantics, by hand. we do have a `focusgroup` impl behind a flag in Chrome, but not shipping yet.
<jarhar> q+
<TabAtkins> flackr: The use of it in my earlier demo used the polyfill
<TabAtkins> ack bkardell_
<bkardell_> q-
<TabAtkins> jarhar: i'm not super familair with the pseudo-element API shape
<TabAtkins> jarhar: kinda seems like these are more element-like than other pseudos
<TabAtkins> jarhar: we had to make some changes to make them receive events in ways other pseudos can't
<TabAtkins> jarhar: we have, in blink, a pseudoelement class that's a subclass of Element so it kinda works
<TabAtkins> jarhar: talking with Tim, he said their pseudos are more strictly different. might be difficult for them to implement.
<TabAtkins> jarhar: wonder if there are any webkit folks around to talk about
<TabAtkins> flackr: good question. pseudos *can* be targeted by clicks and other events. we hide that the pseudo was targeted (use the owner element instead), but i fyou click on a ::before you can listen for the click event
<TabAtkins> jarhar: and you can use like hover pseudoclass?
<TabAtkins> TabAtkins: Yes, and :focus/:active if they're focusable/etc
<bkardell_> maybe we can tag ntim so they can find it when there's time and let us know :)
<TabAtkins> flackr: the CSS pseudo spec has a full definition of PseudoElement interface, subclassing Element, so there's a route to them being full-blown event targets
<TabAtkins> jarhar: okay, probably less crazy than i thought it was
<TabAtkins> ack jarhar