I want to resolve some unreachable cases caused by current spec about determining whether the candidate is on the navigation direction or not.
In the below example, Let's assume that user press right-button from A/C/E.

B and D is reachable from A /C.
According to current spec and chromium, F is not right side of E
*Spec :
https://drafts.csswg.org/css-nav-1/
-> "the item partially overlaps with searchOrigin and its two edges which are orthogonal to dir should be on the navigation direction of the respective ones of searchOrigin."
*Chromium : https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/page/spatial_navigation.cc?q=spatial_navigation.cc&sq=package:chromium&dr&l=117
static inline bool RightOf(const PhysicalRect& a, const PhysicalRect& b) {
return a.X() >= b.Right() || (a.X() >= b.X() && a.Right() > b.Right() &&
a.Y() < b.Bottom() && a.Bottom() > b.Y());
}
I hope to remove "a.Right() > b.Right()" part.
Is there a problem if User can go from E to F using right key?
I would like to know your opinions. (@jihyerish @frivoal @hugoholgersson @Bokand @anawhj )
I simplify the problem and propose the candidate solution via the following example.
https://software.hixie.ch/utilities/js/live-dom-viewer/?saved=7345

The example above shows the current(As Is) behavior of SpatNav (polyfill and Chromium) as follows:
In the figure above, B is considered to be on the right of A, if the left and right edges of B are on the right of the respective ones of A as a rule specified in css-nav spec. For partially overlapping elements, D can't be a candidate if users press a right arrow key from B now. The reason is that the right edge of D isn't on the right of the right edge of B.
For securing D's reachability in a right direction from B, Jeonghee would suggest that we could modify the rule to ways only considering the left edge (of B) on partially overlapping elements when pressing a right arrow key.
It's definitely a heuristic rule that doesn't means a clear solution satisfying all people, but it definitely solves several abnormal behavior(e.g. unreachable element by arrow keys) in several general web sites such as https://naver.com
The modified logic for partially overlapping elements could be specified in css-nav spec as a non-normative, I'm not sure it makes sense. (@jihyerish) Also, I wonder there is something I missed on the logic modification. (@hugoholgersson @bokand)
I think considering 'C' in the above example as a candidate, in general, is risky.
From 'B', and when pressing the right arrow key, 'D' needs to be included in the set of candidates because it'll be unreachable in any direction.
But for 'C', it can be reachable anyway when pressing the up arrow key from 'B'.
It's true that it will solve the issue of https://naver.com, but I'm not sure it will be okay for the other pages.
Therefore I've described how to select the partially overlapped element as the candidate as non-normative in step 4 of selecting the best candidate.
Do Chromium's layout tests pass with this change?
Do Chromium's layout tests pass with this change?
Yes, It did on https://chromium-review.googlesource.com/c/chromium/src/+/1905297
I am planning to add a bug page and resolve conflict soon.
I'm trying to apply new direction rule to chromium likes below. (https://chromium-review.googlesource.com/c/chromium/src/+/1905297/14/)
AS-IS
// if both edges of |a| are below the respective ones of |b|.
static inline bool Below(const PhysicalRect& a, const PhysicalRect& b) {
return a.Y() >= b.Bottom() || (a.Y() >= b.Y() && a.Bottom() > b.Bottom() &&
a.X() < b.Right() && a.Right() > b.X());
}
// For overlapping rects, |a| is considered to be on the right of |b|
// if both edges of |a| are on the right of the respective ones of |b|.
static inline bool RightOf(const PhysicalRect& a, const PhysicalRect& b) {
return a.X() >= b.Right() || (a.X() >= b.X() && a.Right() > b.Right() &&
a.Y() < b.Bottom() && a.Bottom() > b.Y());
TO-BE
```// For overlapping rects, |a| is considered to be below |b|,
// if the top edge of |a| is below the top edge of |b|.
static inline bool Below(const PhysicalRect& a, const PhysicalRect& b) {
return a.Y() >= b.Bottom() ||
(a.Y() > b.Y() && a.X() < b.Right() && a.Right() > b.X());
}
// For overlapping rects, |a| is considered to be above |b|,
// if the bottom edge of |a| is above the bottom edge of |b|.
static inline bool Above(const PhysicalRect& a, const PhysicalRect& b) {
return a.Bottom() <= b.Y() ||
(a.Bottom() < b.Bottom() && a.Right() > b.X() && a.X() < b.Right());
}
// For overlapping rects, |a| is considered to be on the right of |b|,
// if the left edge of |a| is on the right of the left edge of |b|.
static inline bool RightOf(const PhysicalRect& a, const PhysicalRect& b) {
return a.X() >= b.Right() ||
(a.X() > b.X() && a.Y() < b.Bottom() && a.Bottom() > b.Y());
}
// Return true if rect |a| is on the left of |b|. False otherwise.
// For overlapping rects, |a| is considered to be on the left of |b|,
// if the right edge of |a| is on the left of the right edge of |b|.
static inline bool LeftOf(const PhysicalRect& a, const PhysicalRect& b) {
return a.Right() <= b.X() ||
(a.Right() < b.Right() && a.Bottom() > b.Y() && a.Y() < b.Bottom());
}
```
But @hugoholgersson seems to have a different opinion.
I hope to make agreement here.
In below picture,

Let's assume we press DOWN key on "A", "C", "E"
Let's assume we press UP key on "B", "D", "F"
In my opinion and by spec, SpatNav consider only top edge when user press down for overlap case.
So 1-3 and 5-6 are wrong.
@hugoholgersson
I wonder your idea about the rules.
Thanks for the example. It shows how to avoid loops such as [1]. I think you should emphasize this in a code comment and perhaps also in a spec comment.
[1] down, down, down: A, B, A
We avoid [1] thanks to Below()'s a.Y > b.Y. >= would cause [1].
(Please correct me if I'm wrong.)
By the way, why don't we relax the condition on the orthogonal axis? For example:
Below() {
a.Y >= b.Bottom ||
(a.Y > b.Y && a.X <= b.Right && a.Right >= b.X)
}
The current wording does not prevent <= and >= on the X-axis. [2] [3]
[2] _"top edge is below the top edge of searchOrigin鈥檚 boundary box if dir is down"_
[3] _"whose boundary box partially overlaps with inside area of searchOrigin"_
[1] down, down, down: A, B, A
We avoid [1] thanks to Below()'s a.Y > b.Y. >= would cause [1].
Yes right.
why don't we relax the condition on the orthogonal axis? For example:
[2] "top edge is below the top edge of searchOrigin鈥檚 boundary box if dir is down"
Do you think it is overlap even if 1px is attached?
I didn't. but It also makes sense. But it's a bit confusing to tell 1px overlap.
just confusing... I'll fix patch.
I hope there are no different opinion elsewhere in the formula.
Do you think it is overlap even if 1px is attached?
What do you mean by "attached"?

I'm not sure which case is (a.X = b.Right)..
I thought we didn't need to include these two cases as overlap cases.
I wonder your opinion
Good pictures!
Do you think it is overlap even if 1px is attached?
Yes. To me, [2] is overlapping but [1] is not.
I thought we didn't need to include these two cases as overlap cases.
Yeah, I don't know what's best either, but I'd say [2] should be considered "overlapping" even though only 1px overlaps. 1px gets bigger with zooming. :)
I wonder your opinion
With a.X <= b.Right, we include [2] but not [1] so let's use <= in the formula?
Otherwise, I think the formula looks good!
When implementing this in Chrome, you will need to use PhysicalRect::IntersectsInclusively, not PhysicalRect::Intersects.
Thanks for your guide. and I understand your opinion.
I'll use PhysicalRect::IntersectsInclusively and fix "a.X <= b.Right," in this week.
then, I'm going to ping you on chromium review page.