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

Add support for CSS reading-flow #10613

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions images/reading-flow-order-example.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
203 changes: 195 additions & 8 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -3818,6 +3818,11 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
<li><dfn data-x-href="https://drafts.csswg.org/css-display/#inline-formatting-context">inline formatting context</dfn></li>
<li><dfn data-x-href="https://drafts.csswg.org/css-display/#replaced-element">replaced element</dfn></li>
<li><dfn data-x-href="https://drafts.csswg.org/css-display/#css-box">CSS box</dfn></li>
<li><dfn data-x-href="https://drafts.csswg.org/css-display/#css-parent-box">CSS parent box</dfn></li>
<!-- TODO(dizhang168): Update these links and definitions when available. -->
<li><dfn data-x-href="https://drafts.csswg.org/css-display-4/#propdef-reading-flow-container">reading flow container</dfn></li>
<li><dfn data-x-href="https://drafts.csswg.org/css-display-4/#propdef-rendering-defined-sibling-reading-flow">rendering-defined sibling reading flow</dfn></li>
<li>The <dfn data-x-href="https://drafts.csswg.org/css-display-4/#propdef-reading-flow">'reading-flow'</dfn> property</li>
</ul>

<p>The following features are defined in <cite>CSS Flexible Box Layout</cite>:
Expand Down Expand Up @@ -79781,9 +79786,10 @@ dictionary <dfn dictionary>ToggleEventInit</dfn> : <span>EventInit</span> {
<hr>

<p>A node is a <dfn>focus navigation scope owner</dfn> if it is a <code>Document</code>, a
<span>shadow host</span>, a <span>slot</span>, or an element in the <span
<span>shadow host</span>, a <span>slot</span>, an element in the <span
data-x="popover-showing-state">popover showing state</span> which also has a <span>popover
invoker</span> set.</p>
invoker</span> set, a <span>reading-flow-ordered scope owner</span> or a <span>reading flow
item</span>.</p>

<p>Each <span>focus navigation scope owner</span> has a <dfn>focus navigation scope</dfn>, which
is a list of elements. Its contents are determined as follows:</p>
Expand All @@ -79807,6 +79813,12 @@ dictionary <dfn dictionary>ToggleEventInit</dfn> : <span>EventInit</span> {
<li><p>If <var>element</var> is in the <span data-x="popover-showing-state">popover showing
state</span> and has a <span>popover invoker</span> set, then return <var>element</var>.</p></li>

<li><p>If <var>element</var> is a <span>reading-flow-ordered scope owner</span>, then return
<var>element</var>.</p></li>

<li><p>If <var>element</var> is a <span>reading flow item</span>, then return
<var>element</var>.</p></li>

<li><p>Return <var>element</var>'s parent's <span>associated focus navigation owner</span>.</p></li>
</ol>

Expand All @@ -79816,8 +79828,9 @@ dictionary <dfn dictionary>ToggleEventInit</dfn> : <span>EventInit</span> {

<p class="note">The order of elements within a <span>focus navigation scope</span> does not impact
any of the algorithms in this specification. Ordering only becomes important for the
<span>tabindex-ordered focus navigation scope</span> and <span>flattened tabindex-ordered focus
navigation scope</span> concepts defined below.</p>
<span>tabindex-ordered focus navigation scope</span>, <span>flattened tabindex-ordered focus
navigation scope</span> and <span>reading-flow-ordered focus navigation scope</span> concepts
defined below.</p>

<p>A <dfn>tabindex-ordered focus navigation scope</dfn> is a list of <span data-x="focusable
area">focusable areas</span> and <span data-x="focus navigation scope owner">focus navigation
Expand All @@ -79837,7 +79850,15 @@ dictionary <dfn dictionary>ToggleEventInit</dfn> : <span>EventInit</span> {
</ul>

<p>The order within a <span>tabindex-ordered focus navigation scope</span> is determined by each
element's <span>tabindex value</span>, as described in the section below.</p>
element's <span>tabindex value</span>.</p>

<p>A <dfn>reading-flow-ordered focus navigation scope</dfn> is a <span>tabindex-ordered focus
navigation scope</span> whose <span>focus navigation scope owner</span> is a
<span>reading-flow-ordered scope owner</span>.</p>

<p>The order within a <span>reading-flow-ordered focus navigation scope</span> is determined by
the <span>reading flow order</span> only. Each element's <span>tabindex value</span> is used to
determine whether the element is focusable, but it does not affect the order within the scope.</p>

<p class="note">The rules there do not give a precise ordering, as they are composed mostly of
"<!--non-normative-->should" statements and relative orderings.</p>
Expand Down Expand Up @@ -80000,7 +80021,8 @@ dictionary <dfn dictionary>ToggleEventInit</dfn> : <span>EventInit</span> {
regardless.</p>
</dd>

<dt>If the value is a zero</dt>
<dt>If the value is a zero or if the value is a greater than zero and the element is a <span>reading
flow item</span></dt>

<dd>
<p>The user agent must allow the element to be considered as a <span>focusable area</span> and
Expand All @@ -80013,7 +80035,7 @@ dictionary <dfn dictionary>ToggleEventInit</dfn> : <span>EventInit</span> {
<span>shadow-including tree order</span>.</p>
</dd>

<dt>If the value is greater than zero</dt>
<dt>If the value is greater than zero and the element is not a <span>reading flow item</span></dt>

<dd>
<p>The user agent must allow the element to be considered as a <span>focusable area</span> and
Expand Down Expand Up @@ -80067,6 +80089,167 @@ dictionary <dfn dictionary>ToggleEventInit</dfn> : <span>EventInit</span> {
</div>


<div w-nodev>

<h4>The reading flow</h4>

dizhang168 marked this conversation as resolved.
Show resolved Hide resolved
<p>A <dfn>reading-flow-ordered scope owner</dfn> is either: <ref>CSSDISPLAY</ref></p>

dizhang168 marked this conversation as resolved.
Show resolved Hide resolved
<ul>
<li><p>a <span>reading flow container</span>.</p></li>

<li><p>an element <span>delegating its rendering to its children</span> whose <span>CSS parent
box</span> is a <span>reading flow container</span>.</p></li>
</ul>

<p>Every <span>reading-flow-ordered scope owner</span> has an associated <span>reading flow
container</span>.</p>

<p>A <dfn>reading flow item</dfn> is an element whose <span>parent element</span> is a
<span>reading-flow-ordered scope owner</span>.</p>

<p>The <dfn>reading flow order</dfn> of a <span>reading-flow-ordered focus navigation scope</span> <var>scope</var> is the ordered list of elements constructed as follows:</p>

<ol>
<li><p>Let <var>output</var> be an empty <span>list</span>.</p></li>

<li><p>Let <var>owner</var> be the <span>focus navigation scope owner</span> of
<var>scope</var>.</p></li>
dizhang168 marked this conversation as resolved.
Show resolved Hide resolved

<li><p>Let <var>container</var> be the <span>reading flow container</span> associated with
<var>owner</var>.</p></li>

<li><p>Let <var>items</var> be the <span>rendering-defined sibling reading flow</span> of
<var>container</var>.</p></li>

<li>
<p><span data-x="list iterate">For each</span> <var>item</var> of <var>items</var>:</p>
dizhang168 marked this conversation as resolved.
Show resolved Hide resolved

<ol>
<li><p><span>While</span> <var>item</var> is an element that is not the
<var>container</var>:</p></li>
dizhang168 marked this conversation as resolved.
Show resolved Hide resolved

<ol>
<li>
<p>If <var>item</var>'s <span>focus navigation scope owner</span> is <var>owner</var>:</p>

<ol>
<li><p>If <var>output</var> does not <span data-x="list contains">contain</span>
<var>item</var>, <span data-x="list append">append</span> <var>item</var> to
<var>output</var>.</p></li>

<li><p><span>Break</span>.</p></li>
</ol>
</li>

<li><p>Set <var>item</var> to the parent element of <var>item</var> within the <span>flat
tree</span>.</p></li>
</ol>
</ol>
</li>

<li>
<p><span data-x="list iterate">For each</span> <var>child</var> of <var>owner</var> element's
children:</p>

<ol>
<li><p>If <var>child</var>'s <span>focus navigation scope owner</span> is <var>owner</var> and
<var>output</var> does not <span data-x="list contains">contain</span> <var>child</var>, <span
data-x="list append">append</span> <var>child</var> to <var>output</var>.</p></li>
</ol>
</li>

<li><p>Return <var>output</var>.</p></li>

</ol>

<div class="example">

<p>The following shows an example of how to compute the reading flow order.</p>

<pre><code class="html">&lt;!DOCTYPE html>
&lt;html lang="en">
&lt;head>
&lt;style>
.wrapper { display: grid; reading-flow: grid-order; }
&lt;/style>
&lt;/head>
&lt;body>
&lt;div class="wrapper" tabindex="0">
&lt;div id="A" tabindex="0" style="order: 1">A
&lt;div id="B" tabindex="1">B&lt;/div>
&lt;/div>
&lt;div id="DC" tabindex="0" style="display: contents">
&lt;div id="C" tabindex="0" style="order: 3">C
&lt;div id="D" tabindex="0">D&lt;/div>
&lt;div id="E" tabindex="2">E&lt;/div>
&lt;/div>
&lt;div id="F" tabindex="0" style="order: 2">F&lt;/div>
&lt;/div>
&lt;div id="PA" style="position: absolute; left: 100px;" tabindex="0">
&lt;div id="G" tabindex="0">G&lt;/div>
&lt;/div>
&lt;div id="H" tabindex="0" style="order: 4">H&lt;/div>
&lt;/div>
&lt;/body>
&lt;/html></code></pre>

<p><img src="/images/reading-flow-order-example.svg" width="500" height="350" alt=""
class="darkmode-aware"></p>

<p>For a reading-flow-ordered focus navigation scope where wrapper is the focus scope owner:</p>

<ol>
<li><p>Let output be [].</p></li>

<li><p>Let owner be wrapper.</p></li>

<li><p>Let container be wrapper.</p></li>

<li><p>The rendering-defined sibling reading flow is sorted by the CSS order attribute. The
items list is [A, F, C, H]. </p></li>

<li><p>Looping through the items, F and C do not have wrapper as its owner, but its parent DC
do. Output is now [A, DC, H].</p></li>

<li><p>Looping through the children of wrapper, we find PA as not visited reading flow item of
owner. Output is now [A, DC, H, PA].</p></li>

<li><p>Return output [A, DC, H, PA].</p></li>
</ol>

<p>For a reading-flow-ordered focus navigation scope where display: contents DC is the focus
scope owner:</p>

<ol>
<li><p>Let output be [].</p></li>

<li><p>Let owner be DC.</p></li>

<li><p>Let container be wrapper.</p></li>

<li><p>The rendering-defined sibling reading flow is sorted by the CSS order attribute. The
items list is [A, F, C, H]. </p></li>

<li><p>Looping through the items, only F and C's owner is DC. Output is now [F, C].</p></li>

<li><p>Looping through the children of DC, there are no more child to append.</p></li>

<li><p>Return output [F, C].</p></li>
</ol>

<p>Note that A, C, F, PA and H are focus scope owners because they are reading flow items. They
will follow a tabindex-ordered focus navigation scope and the ordering is not affected by the
CSS reading-flow property. In the focus navigation scope of C, the focus order will be [E, D]
because E has a positive tabindex.</p>

<p>Combining everything together, the flattened tabindex-ordered focus navigation scope is:
[Wrapper, A, B, DC, F, C, E, D, H, PA, G].</p>

</div>

</div>

<div w-nodev>

<h4 id="focus-processing-model"><span id="processing-model-5"></span>Processing model</h4>
Expand Down Expand Up @@ -80528,6 +80711,10 @@ dictionary <dfn dictionary>ToggleEventInit</dfn> : <span>EventInit</span> {
scope</span>, the ordering is not necessarily related to the <span>tree order</span> of the
<code>Document</code>.</p>

<p class="note">As a <span>reading-flow-ordered focus navigation scope</span> is a
<span>tabindex-ordered focus navigation scope</span>, it is flattened in <span>reading flow
order</span> into the <span>flattened tabindex-ordered focus navigation scope</span>.</p>

<p>If a <span>focusable area</span> is omitted from the <span>sequential focus navigation
order</span> of its <code>Document</code>, then it is unreachable via <span>sequential focus
navigation</span>.</p>
Expand Down Expand Up @@ -80693,7 +80880,7 @@ dictionary <dfn dictionary>ToggleEventInit</dfn> : <span>EventInit</span> {

<li>
<p>If <var>candidate</var> is a <span>navigable container</span> with a non-null <span>content
navigable</span>, then:</p>
navigable</span>:</p>

<ol>
<li><p>Let <var>recursive candidate</var> be the result of running the <span>sequential
Expand Down
Loading