Skip to content

Commit

Permalink
Define reading flow order algorithm, add example and other improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
dizhang168 committed Nov 13, 2024
1 parent 5b543f6 commit 9fa15ee
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 90 deletions.
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.
255 changes: 165 additions & 90 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -3818,13 +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>The <dfn data-x-href="https://drafts.csswg.org/css-display-4/#valdef-reading-flow-flex-visual">'flex-visual'</dfn>,
<dfn data-x-href="https://drafts.csswg.org/css-display-4/#valdef-reading-flow-flex-flow">'flex-flow'</dfn>,
<dfn data-x-href="https://drafts.csswg.org/css-display-4/#valdef-reading-flow-grid-rows">'grid-rows'</dfn>,
<dfn data-x-href="https://drafts.csswg.org/css-display-4/#valdef-reading-flow-grid-columns">'grid-columns'</dfn>, and
<dfn data-x-href="https://drafts.csswg.org/css-display-4/#valdef-reading-flow-grid-order">'grid-order'</dfn> values of the
<dfn data-x-href="https://drafts.csswg.org/css-display-4/#propdef-reading-flow">'reading-flow'</dfn> property</li>
<li><dfn data-x-href="https://drafts.csswg.org/css-display-4/#order-modified-document-order">order-modified document order</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 @@ -3971,9 +3969,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
<li>The <dfn data-x-href="https://drafts.csswg.org/css-writing-modes/#direction">'direction'</dfn> property</li>
<li>The <dfn data-x-href="https://drafts.csswg.org/css-writing-modes/#unicode-bidi">'unicode-bidi'</dfn> property</li>
<li>The <dfn data-x-href="https://drafts.csswg.org/css-writing-modes/#propdef-writing-mode">'writing-mode'</dfn> property</li>
<li>The <dfn data-x-href="https://drafts.csswg.org/css-writing-modes/#writing-mode">writing
mode</dfn>,
<dfn data-x-href="https://drafts.csswg.org/css-writing-modes/#block-flow-direction">block flow direction</dfn>,
<li>The <dfn data-x-href="https://drafts.csswg.org/css-writing-modes/#block-flow-direction">block flow direction</dfn>,
<dfn data-x-href="https://drafts.csswg.org/css-writing-modes/#block-axis">block axis</dfn>,
<dfn data-x-href="https://drafts.csswg.org/css-writing-modes/#inline-axis">inline axis</dfn>,
<dfn data-x-href="https://drafts.csswg.org/css-writing-modes/#block-size">block size</dfn>,
Expand Down Expand Up @@ -79792,8 +79788,8 @@ dictionary <dfn dictionary>ToggleEventInit</dfn> : <span>EventInit</span> {
<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>, an element in the <span
data-x="popover-showing-state">popover showing state</span> which also has a <span>popover
invoker</span> set, a <span>reading flow container scope owner</span> or a <span
data-x="reading-flow-item">reading flow item</span>.</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 @@ -79817,8 +79813,11 @@ 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 container scope owner</span> or a <span
data-x="reading-flow-item">reading flow item</span>, 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 Down Expand Up @@ -79854,8 +79853,12 @@ dictionary <dfn dictionary>ToggleEventInit</dfn> : <span>EventInit</span> {
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
container scope owner</span>. Its order is determined by the <span>reading flow order</span>.</p>
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 @@ -80018,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 @@ -80031,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 @@ -80089,76 +80093,160 @@ dictionary <dfn dictionary>ToggleEventInit</dfn> : <span>EventInit</span> {

<h4>The reading flow</h4>

<p>A <dfn>reading flow container</dfn> is either: <ref>CSSDISPLAY</ref></p>
<p>A <dfn>reading-flow-ordered scope owner</dfn> is either: <ref>CSSDISPLAY</ref></p>

<ul>
<li><p>A <dfn data-x-href="https://drafts.csswg.org/css-flexbox-1/#flex-container">flex
container</dfn> that has the <span>'reading-flow'</span> CSS property set to
<span>'flex-visual'</span> or <span>'flex-flow'</span>.</p></li>
<li><p>a <span>reading flow container</span>.</p></li>

<li><p>A <dfn data-x-href="https://drafts.csswg.org/css-grid-2/#grid-container">grid
container</dfn> that has the <span>'reading-flow'</span> CSS property set to
<span>'grid-rows'</span>, <span>'grid-columns'</span> or <span>'grid-order'</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>A <dfn>reading flow container scope owner</dfn> is either:</p>
<p>Every <span>reading-flow-ordered scope owner</span> has an associated <span>reading flow
container</span>.</p>

<ul>
<li><p>a <span>reading flow container</span>.</p></li>
<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>

<li><p>an element <span>delegating its rendering to its children</span> whose <span>parent
element</span> is a <span>reading flow container</span>.</p></li>
</ul>
<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>

<p>A <dfn data-x="reading-flow-item">reading flow item</dfn> is an element whose <span>parent
element</span> is a <span>reading flow container scope owner</span>.</p>
<ol>
<li><p>Let <var>output</var> be an empty <span>list</span>.</p></li>

<p>A <dfn data-x="non-participating-reading-flow-item">non-participating reading flow item</dfn> is
a <span data-x="reading-flow-item">reading flow item</span> whose computed value of the
<span>'display'</span> property is 'contents' or whose computed value of the
<span>'position'</span> property is 'fixed' or 'absolute'.</p>
<li><p>Let <var>owner</var> be the <span>focus navigation scope owner</span> of
<var>scope</var>.</p></li>

<p>A <dfn data-x="participating-reading-flow-item">participating reading flow item</dfn> is a <span
data-x="reading-flow-item">reading flow item</span> that is not a <span
data-x="non-participating-reading-flow-item">non-participating reading flow item</span>.</p>
<li><p>Let <var>container</var> be the <span>reading flow container</span> associated with
<var>owner</var>.</p></li>

<p>The <dfn>reading flow order</dfn> for a <span>reading-flow-ordered focus navigation scope</span>
is determined by the scope owner's computed value of the <span>'reading-flow'</span> property:</p>
<li><p>Let <var>items</var> be the <span>rendering-defined sibling reading flow</span> of
<var>container</var>.</p></li>

<ul>
<li><p>For <span>'flex-visual'</span>: follows the order defined by sorting the <span
data-x="participating-reading-flow-item">participating reading flow items</span> in the visual
reading order of flex items and taking the <span>writing mode</span> into account, followed by
<span data-x="non-participating-reading-flow-item">non-participating reading flow items</span>
in <span>tree order</span>.</p></li>
<li>
<p><span data-x="list iterate">For each</span> <var>item</var> of <var>items</var>:</p>

<li><p>For <span>'flex-flow'</span>: follows the order defined by sorting the <span
data-x="participating-reading-flow-item">participating reading flow items</span> using the
<span>'flex-flow'</span> direction, followed by <span
data-x="non-participating-reading-flow-item">non-participating reading flow items</span> in
<span>tree order</span>.</p></li>
<ol>
<li><p><span>While</span> <var>item</var> is an element that is not the
<var>container</var>:</p></li>

<li><p>For <span>'grid-rows'</span>: follows the order defined by sorting the <span
data-x="participating-reading-flow-item">participating reading flow items</span> first by their
visual row order, and then by their visual column order, taking the <span>writing mode</span>
into account, followed by <span data-x="non-participating-reading-flow-item">non-participating
reading flow items</span> in <span>tree order</span>.</p></li>

<li><p>For <span>'grid-columns'</span>: follows the order defined by sorting the <span
data-x="participating-reading-flow-item">participating reading flow items</span> first by their
visual column order, and then by their visual row order, taking the <span>writing mode</span>
into account, followed by <span data-x="non-participating-reading-flow-item">non-participating
reading flow items</span> in <span>tree order</span>.</p></li>

<li><p>For <span>'grid-order'</span>: follows the order defined by sorting the <span
data-x="participating-reading-flow-item">participating reading flow items</span> in
<span>order-modified document order</span>, followed by <span
data-x="non-participating-reading-flow-item">non-participating reading flow items</span> in
<span>tree order</span>.</p></li>
</ul>
<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>

<p>If a <span data-x="reading-flow-item">reading flow item</span> has a <span>tabindex value</span>
greater than zero, then let its value be readjusted to zero.</p>
</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>

Expand Down Expand Up @@ -80623,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 @@ -80786,23 +80878,6 @@ dictionary <dfn dictionary>ToggleEventInit</dfn> : <span>EventInit</span> {
focusable</span>.</p>
</li>

<li>
<p>If <var>starting point</var> is a <span data-x="reading-flow-item">reading flow item</span>
in a <span>reading-flow-ordered focus navigation scope</span> <var>scope</var>:</p>

<ol>
<li><p>Let <var>reading flow items</var> be the list of <span
data-x="reading-flow-item">reading flow items</span> owned by <var>scope</var>, sorted in
<span>reading flow order</span>.</p></li>

<li><p>If <var>direction</var> is <i>forward</i>, then let <var>candidate</var> be the item
that comes after <var>starting point</var> in <var>reading flow items</var>.</p></li>

<li><p>Otherwise, let <var>candidate</var> be the item that comes before <var>starting
point</var> in <var>reading flow items</var>.</p></li>
</ol>
</li>

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

0 comments on commit 9fa15ee

Please sign in to comment.