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

Make :focus-visible rules work when polyfill not present #145

Merged
merged 1 commit into from
Jul 15, 2021

Conversation

lyzadanger
Copy link
Contributor

@lyzadanger lyzadanger commented Jul 14, 2021

When the focus-visible polyfill is loaded—which it is in our LMS and client projects—that polyfill will assign a .focus-visible class to elements whose heuristics match the intent of :focus-visible, whether or not the browser natively supports :focus-visible or not.

The following rule, as previously written, was meant to suppress outlines on elements if they didn't have the .focus-visible class (which is applied/removed by the polyfill):

&:focus:not(.focus-visible) {
  @include outline--hide;
}

The problem with this selector is that, if the polyfill is not present, it will always match—because the .focus-visible class is
never present—causing all focus outlines to be suppressed, even when the element is :focus-visible. That is, the previous selector was coupled to the presence of the polyfill.

When present, the polyfill also applies a .js-focus-visible class to a container element. We can make the selector here more specific, and include that classname, such that it will only match when the polyfill is actually present:

.js-focus-visible &:focus:not(.focus-visible)

Focus outlines "worked" before in the lms and client projects because the polyfill was also present, but did not work in this project, where we don't load the polyfill. Now this should work correctly in both contexts, and is independent of the polyfill.

Fixes #126

Test it out

Pull this branch, visit the Buttons pattern-library page and try tabbing around between buttons. You should see a focus outline when you tab with a keyboard.

Compare against main where buttons don't show an outline.

Copy link
Contributor

@LMS007 LMS007 left a comment

Choose a reason for hiding this comment

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

Yes, this makes more sense, the rule was too generic and I like this is a tiny tweak to fix it. I'm still wondering why Safari works without the polyfill, but I guess this means it has partial support for the pseudo selector. I wonder we can 100% ditch the polyfill then? Not a decision for today tho!

Great fix!

I tested on client + frontendshared with Chrome+Safari

// Selector for browsers using JS polyfill, which adds the "focus-visible"
// class to a keyboard-focused element.
&:focus:not(.focus-visible) {
.js-focus-visible &:focus:not(.focus-visible) {
Copy link
Contributor

Choose a reason for hiding this comment

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

.js-focus-visible. Is a top level class correct? If thats the case, for clarify I think braces help here as well as putting the & on a second line.

.js-focus-visible {
  &:focus:not(.focus-visible) {
    ...
  }
}



Copy link
Member

@robertknight robertknight left a comment

Choose a reason for hiding this comment

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

Great PR description. The change looks good. I had a suggestion to link to the polyfill's GitHub project in the code comments.

When the `focus-visible` polyfill is loaded—which it is in our LMS and
client projects—that polyfill will assign a `.focus-visible` class to
elements whose heuristics match the intent of `:focus-visible`, whether
or not the browser natively supports `:focus-visible` or not.

This rule, as previously written, was meant to suppress outlines on
elements if they didn't have the `.focus-visible` class:

```
&:focus:not(.focus-visible) {
  @include outline--hide;
}
```

The problem with this selector is that, if the polyfill is not
present, it will always match—because the `.focus-visible` class is
never present—causing all focus outlines to be suppressed, even when the
element is `:focus-visible`. That is, the previous selector was coupled
to the presence of the polyfill.

When present, the polyfill also applies a `.js-focus-visible` class to a
container element. We can make the selector here more specific, and
include that classname, such that it will only match when the polyfill
is actually present:

`.js-focus-visible &:focus:not(.focus-visible)`

Focus outlines "worked" before in the `lms` and `client` projects
because the polyfill was also present, but did not work in this project,
where we don't load the polyfill. Now this should work correctly in
both contexts.
@codecov
Copy link

codecov bot commented Jul 15, 2021

Codecov Report

Merging #145 (e941fd6) into main (aa22822) will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff            @@
##              main      #145   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           12        12           
  Lines          149       149           
  Branches        50        50           
=========================================
  Hits           149       149           

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update aa22822...e941fd6. Read the comment docs.

@lyzadanger lyzadanger merged commit ca8b48f into main Jul 15, 2021
@lyzadanger lyzadanger deleted the fix-focus-visible branch July 15, 2021 12:47
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.

Figure out what's going on with focus and button styling
3 participants