这是indexloc提供的服务,不要输入任何密码
Skip to content

Conversation

@Merri
Copy link

@Merri Merri commented Nov 25, 2020

Reach Router uses a focus wrapper element which is used to contain focus when no other element has it. It gains focus on initial page load, and it is used as a focus target when route is changed in SPA mode to recreate the native browser-like focus management upon switching page.

The wrapper element is rendered as:

<div style="outline:none" tabindex="-1" id="gatsby-focus-wrapper">

In general tabindex="-1" elements can only be focused without a keyboard so we should probably always ignore them.

Why is this needed

Without this change focus-visible styles are incorrectly applied to Reach Router's focus wrapper element. Also without this change the 100ms timeout in onBlur will incorrectly assume user is switching tabs if a client-side redirect occurs upon page loading and as a result element is focused by code as a side-effect. This results into a bug where focus-visible toggles style on the focused element upon fresh page load where user has not used the keyboard at all.

Other thoughts

onBlur might need some adjustments to remove the possibility to trigger incorrectly upon focus by code triggering on initial page load. However this proposed change already greatly reduces the chance of focus style triggering incorrectly.

Reach Router uses a focus wrapper element which is used to contain focus when no other element has it. It is used as a focus target when route is changed in SPA mode.

In general `tabindex="-1"` elements can only be focused without a keyboard so we should probably always ignore them.
@Justineo
Copy link
Contributor

Elements with tabindex="-1" can be focused programatically and receive a :focus-visible state. The current behavior is currently consistent with Chrome's native :focus-visible implementation.

@yoavweiss
Copy link
Contributor

@Merri - can you join the WICG to appease the IPR bots?

@Merri
Copy link
Author

Merri commented Nov 25, 2020

Joined, but it didn't get reflected here.

The core issue is that Reach Router does one focus, and if a developer needs to do another focus to an element (such as modal opening) then we have two programatical .focus() calls within 100ms which then trigger focus-visible style active. This does not match :focus-visible nor -moz-focusring behavior. I guess the only way around would be to re-think how onBlur's switching between browser tabs is detected.

@eps1lon
Copy link
Contributor

eps1lon commented Nov 25, 2020

This results into a bug where focus-visible toggles style on the focused element upon fresh page load where user has not used the keyboard at all.

:focus-visible is applied to the very first focus without any user-action. So if you programmatically focus something on the initial page load then it gets :focus-visible.

In general tabindex="-1" elements can only be focused without a keyboard so we should probably always ignore them.

They can be programmatically focused by an action triggered by keyboard input. For example, in https://codesandbox.io/s/sweet-breeze-9dqc0?file=/src/App.js, tab to the button, hit enter. The wrapper has the native :focus-visible styles even though it has tabIndex="-1".

:focus-visible always looks at the last modality. So if your last input came from keyboard then any focus() will apply :focus-visible. Even if that focus was programmatic, came 30 minutes later and targets a [tabindex="-1"].

See

If focus is moved programmatically by calling focus(), the newly focused element will only match :focus-visible if the previously focused element matched it as well.

-- https://blog.chromium.org/2020/09/giving-users-and-developers-more.html (:focus-visible heuristic)

@Merri
Copy link
Author

Merri commented Nov 25, 2020

Thanks for the clarifications and also the quick responses! These helped me better understand a bug I worked on yesterday. I might have made a wrong conclusion (or a mistake) on :focus-visible behavior vs. focus-visible while testing it, and debugging through a lot of other third party code. The bug itself is resolved and just to be sure I'll also blacklist the focus wrapper from gaining any styles:

.focus-wrapper:not(#gatsby-focus-wrapper) {}

As giving box-shadow to a container element of everything is a performance hit, especially on mobile.

Closing the PR.

@Merri Merri closed this Nov 25, 2020
@Merri Merri deleted the patch-1 branch November 25, 2020 11:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants