Skip to content

Commit

Permalink
[css-overflow-5] Define scroll-markers (#10243)
Browse files Browse the repository at this point in the history
Define scroll-markers pseudo-elements, scrolltarget attribute and associated behaviors.
  • Loading branch information
flackr committed Jun 13, 2024
1 parent a660292 commit 278efac
Showing 1 changed file with 174 additions and 2 deletions.
176 changes: 174 additions & 2 deletions css-overflow-5/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,21 @@ Introduction</h2>

This specification extends [[!CSS-OVERFLOW-4]].

: [[#scroll-marker-group|Scroll marker groups]]
::
This section defines pseudo-elements for automatically constructed [[#scroll-navigation|scroll navigation controls]].

: [[#fragmentation|Redirection of Overflow]]
::
This section defines a highly experimental, exploratory new model
for handling overflow by redirecting it into newly-generated [=fragmentation containers=].

: [[#scroll-navigation|Scroll navigation controls]]
::
This section defines stylable scroll navigation controls
with defined user interactions and accessible labels.


Note: At the time of writing, [[CSS-OVERFLOW-4]] is not completely finalized yet.
To avoid accidental divergences and maintenance overhead,
This specification is written as a delta specification over css-overflow Level 4.
Expand All @@ -148,6 +158,67 @@ its content will be integrated into this specification,
which will then replace it.
Until then, this specification only contains additions and extensions to level 4.

<h3 id="scroll-marker-group">
Overflow Controls: the 'scroll-marker-group' property and pseudo-elements</h3>

<pre class=propdef>
Name: scroll-marker-group
Value: none | before | after
Initial: none
Applies to: [=scroll containers=]
Inherited: no
Computed value: specified value
Animation Type: discrete
Canonical Order: per grammar
</pre>

The 'scroll-marker-group' property specifies whether the [=scroll container=] should have a '::scroll-marker-group' pseudo-element created,
and its position relative to the scroll container.

<dl dfn-type=value dfn-for=scroll-marker-group>
<dt><dfn>none</dfn>
<dd>
The [=scroll container=] does not create a '::scroll-marker-group' pseudo-element.

<dt><dfn>before</dfn>
<dd>
The [=scroll container=] generates a ''::scroll-marker-group'' pseudo-element
whose box is an immediate preceding sibling to its [=originating element=].

<dt><dfn>after</dfn>
<dd>
The [=scroll container=] generates a ''::scroll-marker-group'' pseudo-element
whose box is an immediate following sibling to its [=originating element=].

</dl>

<h4 id="scroll-marker-group-pseudo">The ''::scroll-marker-group'' pseudo-element</h4>

The <dfn selector>::scroll-marker-group</dfn> pseudo-element box
is generated by a [=scroll container=] element
having a computed 'scroll-marker-group' property that is not 'none',
representing a stylable sibling pseudo-element immediately adjacent to the [=scroll container=].

The following additions are recommended for the default UA stylesheet
to ensure that the generation of scroll marker pseudo-elements does not invalidate the layout of the site:

<pre class="lang-css">
/* The generation of ::scroll-marker pseudo-elements cannot invalidate layout outside of this pseudo-element. */
::scroll-marker-group { contain: size !important; }
</pre>

<h4 id="scroll-marker-pseudo">The ''::scroll-marker'' pseudo-element</h4>

When the computed 'content' value of a <dfn selector>::scroll-marker</dfn> pseudo-element is not 'none'
and its nearest ancestor [=scroll container=] [=scroll container=] has a computed 'scroll-marker-group' property that is not 'none',
the pseudo-element generates a box attached as a child of the ''::scroll-marker-group'' pseudo-element's generated box
on its nearest ancestor [=scroll container=].
These boxes are added in the [=tree order=] of their <a>originating element</a>.

These pseudo-elements behave as a <{button}>
with {{HTMLButtonElement/scrollTargetElement}} set to its <a>originating element</a>.
They can be focused and invoked.

<h2 id="fragmentation" class=no-num>
Appendix A: Redirection of Overflow</h2>

Expand Down Expand Up @@ -807,14 +878,115 @@ the ''continue/fragments'' value of the 'continue' property.
</td></tr></table>
</div>

<h2 id="scroll-navigation">
Appendix B: Scroll navigation controls</h2>

[[html#the-a-element]] allows creating navigational links to a particular scroll position within the same page.
However, there is little feedback to the user regarding the current content being viewed, and
the interaction model does not match the expectations of modern accessible UI components.

This specification adds a mechanism for creating scroll navigation controls.
The active marker, reflecting the current position, can be styled to give the user an indication of which section they are in.
The set of markers are treated as a component following the accessibility guidelines for keyboard navigation within components.

Use cases include a table of contents with links to relevant contents,
markers for scrolling carousel pages,
and scrollable tab panels.

Issue: Add images representing these examples.

Issue: Explore whether scrolltarget can be more directly associated with anchor tags.

<h3 id="scroll-target"><{button/scrolltarget}> attribute</h3>

The <dfn element-attr for=button>scrolltarget</dfn> attribute turns a <{button}> element into a [=scroll marker control=].
This takes the ID of the element to target as its value.

The <dfn attribute for=HTMLButtonElement lt=scrollTargetElement>HTMLButtonElement.scrollTargetElement</dfn> instance property
gets and sets the element being interacted with by the control button.
This is the JavaScript equivalent of the <{button/scrolltarget}> HTML attribute.

A 'button' with a non-null {{HTMLButtonElement/scrollTargetElement}}
represents a <dfn export>scroll marker control</dfn> that forms a <dfn>scroll marker group</dfn> for its nearest [=scroll container=]
in which exactly one control in the group can have its 'checked' state set to true.
A [=scroll marker control=] with a true 'checked' state can be styled by the '':checked'' pseudo-class.

The [=scroll marker group=] that contains a <{button}> element a also contains all the other <{button}> elements b that fulfill the following conditions:

* The <{button}> element b has a non-null {{HTMLButtonElement/scrollTargetElement}} value.
* a and b's {{HTMLButtonElement/scrollTargetElement}} have the same nearest [=scroll container=].

<div algorithm="scrollTargetElement activation">
When a [=scroll marker control=] is activated:

1. Let <var>element</var> be the {{HTMLButtonElement/scrollTargetElement}} of the control.
1. Let <var>block</var> be "<code>start</code>".
1. Let <var>inline</var> be "<code>start</code>".
1. <a lt='scroll a target into view'>Scroll the element into view</a> with <var>behavior</var>, <var>block</var>, and <var>inline</var>.
1. If activated by invocation, move focus to <var>element</var>.
If <var>element</var> is not focusable this will result in there being no active element,
but the next focus change will proceed from this <var>element</var> as if it were focused.
</div>

Issue: Moving focus to the control on activation means that the only way to control scroll markers via the keyboard is to tab into them.
We should retain focus after the control is activated, while still altering the point from which the next focusable element is found if the user tabs away.

<h4 id="scroll-container-scroll">Scroll tracking</h4>

A scrolling operation might animate towards a particular position
(e.g. scrollbar arrow clicks, arrow key presses, "behavior: smooth" programmatic scrolls)
or might directly track a user’s input
(e.g. touch scrolling, scrollbar dragging).
In either case, the user agent chooses an 'eventual scroll position' to which the scroller
will reach.

This 'eventual scroll position' is used to determine the active marker.
Since markers themselves may represent just the start of the content (e.g. headers), we consider the active marker to be the first one which we are at or beyond the scroll position of.

<div algorithm="scroll tracking">
Whenever a [=scroll container=] is scrolled, or layout changes the scroll position, the user agent must run these steps to determine the active marker:

1. Let <var>position</var> be the 'eventual scroll position' for the scrolling operation.
1. Let <var>markers</var> be all of the [=scroll marker control=] elements which are a part of the [=scroll marker group=] for the [=scroll container=].
1. Let <var>targets</var> be the set of {{HTMLButtonElement/scrollTargetElement}} for those controls sorted in [=tree order=].
1. Let <var>selected</var> be the first element in <var>targets</var>, or null if <var>targets</var> is empty.
1. For each <var>target</var> in <var>targets</var>:
1. Set <var>selected</var> to <var>target</var>.
1. Let <var>targetPosition</var> be the position that would be scrolled to if we scroll <var>target</var> into view.
1. : If <var>targetPosition</var>'s scroll block offset is less than or equal to <var>position</var>'s scroll block offset, and
<var>targetPosition</var>'s scroll inline offset is less than or equal to <var>position</var>'s scroll inline offset.
::
Update <var>selected</var> to <var>target</var>.
Break.
1. : If <var>selected</var> is not null,
::
1. Let <var>marker</var> be the first control in <var>markers</var> whose {{HTMLButtonElement/scrollTargetElement}} is <var>selected</var>.
1. Set the 'checked' state of <var>marker</var> to true.
: Otherwise,
::
Set the 'checked' state of all controls in <var>markers</var> to false.
</div>

Issue: Should we allow for none of the markers to be currently active, e.g. if not yet scrolled past the position of the first marker.

<h4 id="scroll-target-focus">Focus behavior</h4>

A [=scroll marker control=] is only focusable if it is 'checked'. Within a group, exactly one marker is 'checked' at a time.

When such a control is focused,
* The down arrow or right arrow move focus to and activate the next control from its [=scroll marker group=].
* The up arrow or left arrow move focus to and activate the previous control from its [=scroll marker group=].
* Space or Enter invoke the control.

Issue: We should be able to tab away from the target immediately after using arrow navigations rather than requiring activating the control first.

<h2 id=privclass=nonum>
Appendix B: Privacy Considerations</h2>
Appendix C: Privacy Considerations</h2>

This specification introduces no new privacy considerations.

<h2 id=sec class=nonum>
Appendix C: Security Considerations</h2>
Appendix D: Security Considerations</h2>

This specification introduces no new security considerations.

Expand Down

0 comments on commit 278efac

Please sign in to comment.