Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 97 additions & 35 deletions css-nav-1/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -1041,11 +1041,11 @@ Issue(w3c/csswg-drafts#2324): CSS should have a term for “border box taking in

To <dfn lt="find focusable areas | finding focusable areas">find focusable areas</dfn> within a containing element <var>C</var>,
with an optional <var>visibleOnly</var> argument that defaults to <code>true</code>,
follow the following steps:
run the following steps:

1. Let <var>focusables</var> be the <a spec=infra for="/">set</a> of all the <a>focusable areas</a> whose [=DOM anchor=] are descendants of <var>C</var>.
In the case of [=boxes=] with several [=box fragments=], each [=box fragment=] is considered separately.
2. The UA should <a spec=infra for=set>remove</a> from <var>focusables</var> items that have a [=DOM anchor=] whose <a element-attr spec=html><code>tabindex</code></a> attribute is set to a negative value.
2. The User Agent should <a spec=infra for=set>remove</a> from <var>focusables</var> items that have a [=DOM anchor=] whose <a element-attr spec=html><code>tabindex</code></a> attribute is set to a negative value.

Note: This is a "SHOULD" in order to mirror the exclusion of elements with negative tabindex
from the <a>sequential focus navigation order</a> as defined in [[HTML#the-tabindex-attribute]].
Expand Down Expand Up @@ -1087,7 +1087,7 @@ To <dfn lt="select the best candidate | selecting the best candidate">select the
within a <a spec=infra for="/">set</a> of <var>candidates</var>
in a direction <var>dir</var>,
starting from <var>searchOrigin</var>,
follow the following steps:
run the following steps:

1. If <var>candidates</var> is <a spec=infra for=set>empty</a>, return <code>null</code>
2. If <var>candidates</var> contains a single item, return that item
Expand All @@ -1098,19 +1098,19 @@ follow the following steps:
4. Let <var>insiders</var> be the subset of <var>candidates</var> items
whose [=DOM anchor=] are descendants of <var>searchOrigin</var>
and whose <a>boundary box</a>'s
* top edge is below the top edge of <var>insideArea</var> if <var>D</var> is <code>down</code>
* bottom edge is above the bottom edge of <var>insideArea</var> if <var>D</var> is <code>up</code>
* right edge is left of the right edge of <var>insideArea</var> if <var>D</var> is <code>left</code>
* left edge is right of the left edge of <var>insideArea</var> if <var>D</var> is <code>right</code>
* top edge is below the top edge of <var>insideArea</var> if <var>dir</var> is {{SpatialNavigationDirection/down}}
* bottom edge is above the bottom edge of <var>insideArea</var> if <var>dir</var> is {{SpatialNavigationDirection/up}}
* right edge is left of the right edge of <var>insideArea</var> if <var>dir</var> is {{SpatialNavigationDirection/left}}
* left edge is right of the left edge of <var>insideArea</var> if <var>dir</var> is {{SpatialNavigationDirection/right}}

Note: this sub-setting is necessary to avoid going in the opposite direction than the one requested.
5.
* If <var>insiders</var> is non empty
1. Let <var>closest subset</var> be the subset of <var>insiders</var> whose <a>boundary box</a>'s
* top edge is closest to the top edge of <var>insideArea</var> if <var>D</var> is <code>down</code>
* bottom edge is closest to the bottom edge of <var>insideArea</var> if <var>D</var> is <code>up</code>
* right edge is closest to the right edge of <var>insideArea</var> if <var>D</var> is <code>left</code>
* left edge is closest to the left edge of <var>insideArea</var> if <var>D</var> is <code>right</code>
* top edge is closest to the top edge of <var>insideArea</var> if <var>dir</var> is {{SpatialNavigationDirection/down}}
* bottom edge is closest to the bottom edge of <var>insideArea</var> if <var>dir</var> is {{SpatialNavigationDirection/up}}
* right edge is closest to the right edge of <var>insideArea</var> if <var>dir</var> is {{SpatialNavigationDirection/left}}
* left edge is closest to the left edge of <var>insideArea</var> if <var>dir</var> is {{SpatialNavigationDirection/right}}
2. If <var>closest subset</var> contains a single item,
return that item,
else return the first item of <var>closest subset</var> in document order,
Expand All @@ -1123,38 +1123,100 @@ follow the following steps:
1. Set <var>candidates</var> be the subset of its items
whose <a>boundary box</a>'s geometric center is within the closed half plane
whose boundary goes through the geometric center of the <var>searchOrigin</var>
and is perpendicular to <var>D</var>.
and is perpendicular to <var>dir</var>.
2. For each <var>candidate</var> in <var>candidates</var>,
find the points <var>P1</var> inside the <a>boundary box</a> of <var>searchOrigin</var>
and <var>P2</var> inside the <a>boundary box</a> of <var>candidate</var>
that minimize the <var>distance</var> between these two points,
when <var>distance</var> is defined as follows:

<dl>
<dt><var>distance</var>:
<dd><var>A</var> + <var>B</var> + <var>C</var> - <var>D</var>

<dt><var>A</var>:
<dd>The euclidian distance between <var>P1</var> and <var>P2</var>

<dt><var>B</var>:
<dd>The absolute distance in the <var>dir</var> direction between <var>P1</var> and <var>P2</var>

<dt><var>C</var>:
<dd>The absolute distance in the direction which is orthogonal to <var>dir</var> between <var>P1</var> and <var>P2</var>

<dt><var>D</var>:
<dd>The square root of the area of intersection between the <a>boundary boxes</a> of <var>candidate</var> and <var>searchOrigin</var>
</dl>
3. Return the item of the <var>candidates</var> set that has the smallest <var>distance</var>.
1. If the <var>searchOrigin</var> is an element, then find the points <var>P1</var> inside the <a>boundary box</a>
of <var>searchOrigin</var> and P2 inside the boundary box of <var>candidate</var>.
2. Else if the <var>searchOrigin</var> is a point, then let the point <var>P1</var> be the <var>searchOrigin</var>
and find the point <var>P2</var> inside the <a>boundary box</a>.
3. Let <var>intersectRect</var> be an <dfn>intersecting area</dfn> between the search origin and a candidate.
4. Select the <var>P1</var> and <var>P2</var> that make the smallest <var>distance</var> between those two points by
<a>calculating the distance</a>.
5. Return the item of the <var>candidates</var> set that has the smallest <var>distance</var>.
If several have the same distance,
return the first one in document order,
unless its [=boundary box=] overlaps with the [=boundary box=] of an other item at the same distance,
and that item is higher in the CSS [=painting order=].
In that case, return that item instead,
unless it too is overlapped with another higher item at the same distance, recursively.
unless it too is overlapped with another higher item at the same distance, recursively.
</div>

<div algorithm="to calculate the distance">
To <dfn lt="calculating the distance | to calculate the distance">calculate the <var>distance</var></dfn>, the function is defined as below:

<pre class="prod">
<var>distance</var> = <var>euclidian</var> + <var>displacement</var> - <var>alignment</var> - <var>sqrt(Overlap)</var>
</pre>

The meaning of each factor in the function is as follows:

<dl dfn-type="value" dfn-for="spatial-navigation-distance-function">
<dt><var>euclidian</var>
<dd>The euclidian distance between <var>P1</var> and <var>P2</var>

<dt><var>displacement</var>
<dd>The degree of displacement in <var>dir</var> between <var>searchOrigin</var> and <var>candidate</var>
<dd>Defined as <pre class="prod">(absolute distance on the axis orthogonal to <var>dir</var> + <var>orthogonalBias</var>) * <var>orthogonalWeight</var></pre>

* <var>orthogonalBias</var>
* If the <var>dir</var> is {{SpatialNavigationDirection/left}} or {{SpatialNavigationDirection/right}},
height of <var>searchOrigin</var> / 2
* Else if the <var>dir</var> is {{SpatialNavigationDirection/up}} or {{SpatialNavigationDirection/down}},
width of <var>searchOrigin</var> / 2

* <var>orthogonalWeight</var>:
* If the <var>dir</var> is {{SpatialNavigationDirection/left}} or {{SpatialNavigationDirection/right}}, 30
* Else if the <var>dir</var> is {{SpatialNavigationDirection/up}} or {{SpatialNavigationDirection/down}}, 2

<dt><var>alignment</var>
<dd>The degree of alignment in <var>dir</var> between <var>searchOrigin</var> and <var>candidate</var>
<dd>Defined as <pre class="prod"><var>alignBias</var> * <var>alignWeight</var></pre>

* <var>alignBias</var>

* If the <var>dir</var> is {{SpatialNavigationDirection/left}} or {{SpatialNavigationDirection/right}},
height of <var>intersectRect</var> / height of <var>candidate</var>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In #3388 you wrote "length of the edge of the search origin". Here you wrote candidate's edge" instead... Mistake?

Copy link
Member

@anawhj anawhj May 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The edge of search origin on the comment (#3388) has been replaced with the current expression on the spec which describes an edge of candidate. If you have another opinion, please put it here or make an issue so that we could consider. With minor updates (figures of some weights), we are going to apply the updated expression into Blink.

BTW, the polyfill would operate it with the edge of search origin that seems not to match with the current spec. @jihyerish please check and update on it.
https://github.com/WICG/spatial-navigation/blob/master/polyfill/spatial-navigation-polyfill.js#L1059

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created crbug.com/958845 for the Blink work.

See this example:

   ____________________ top edge of container or other focusable. 20 units wide.
   YYYYY XXXXXXXXXXXX

Here we want X to win so we do 12/20 .

12 / 20 > 5 / 20 => we give X a larger alignment because we want to decrease the distance to X more than we decrease the distance to Y. (alignment is a negative term in the formula).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you're right. My mistake...
Thanks for pointing this out! I'll fix this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been fixed by bfe77ef.

* Else if the <var>dir</var> is {{SpatialNavigationDirection/up}} or {{SpatialNavigationDirection/down}},
width of <var>intersectRect</var> / width of <var>candidate</var>

* <var>alignWeight</var> is 5

<dt><var>sqrt(Overlap)</var>
<dd>The square root of an <a>overlapping area</a> between the <a>boundary boxes</a> of <var>searchOrigin</var> and <var>candidate</var>
<dd>Let <var>overlapRect</var> be
<var>intersectRect</var> if the <a>overlapping area</a> exists,
and 0 otherwise.
<dd>Defined as <pre class="prod">sqrt(height of <var>overlapRect</var> * width of <var>overlapRect</var>)</pre>
</dl>

NOTE: The values of <var>alignWeight</var> and <var>orthogonalWeight</var> in the function are decided based on
the collected <a href="https://wicg.github.io/spatial-navigation/tests/ux/list.html">UX test cases</a>.
It aims to show the generally expected result in the real pages.
Everyone is welcome to contribute to the test cases!

<div class='example'>
This example shows how the <a>intersecting area</a>(<var>intersectRect</var>) is defined.

<figure>
<img alt="" src="images/intersecting-area-1.png" style="height: 200px;"/>
<figcaption>The <a>intersecting area</a> when there is the <a>overlapping area</a>.</figcaption>
</figure>

The figure above is the simplest case to define the <a>intersecting area</a>.
The <dfn>overlapping area</dfn> is the geometric overlap region between the two elements.
In this case, the <a>intersecting area</a> is the same as the <a>overlapping area</a> without reference to the direction of the navigation.

<figure>
<img alt="" src="images/intersecting-area-2.png" style="height: 200px;"/>
<figcaption>The <a>intersecting area</a> when the elements are aligned.</figcaption>
</figure>

In the case above, the search origin element and the candidate element are aligned and the requested direction is {{SpatialNavigationDirection/right}}.
The <a>intersecting area</a> is created with
(1) The gap between two elements.
(2) The parts of the edges from each element which are overlapped
when the right edge of the search origin element and the left edge of the candidate are projected to each other.
</div>
</div>

<div class=cssapi>
Expand Down
Binary file added css-nav-1/images/intersecting-area-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added css-nav-1/images/intersecting-area-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.