I have CSS like this
*:focus-visible {
outline: 2px solid blue; /* This value is dynamically set based on configuration */
}
I now have a button with class toggle
that has
.toggle {
/* ... many other styles */
outline: none;
}
This outline: none
is to prevent the default focus outline from showing when the button is clicked. However, I’d now like the focus-visible
style defined above to apply to it, since focus-visible
styles are only applied in more specific cases, when the focus really should be visible, not just when the button is clicked.
I half expected something like this to work:
.toggle:focus-visible {
outline: inherit;
}
But if I understand this correctly, inherit
does not mean it’s inheriting the value from the parent’s focus-visible
styles. Is there any way to do this without the .toggle
styles having to duplicate the value set earlier? In other words, is there some way to have it "fall back"?
2
Answers
Set the initial value of outline (which is none) when element is unfocused.
There is no way (AFAIK) to reset a value to what was set in another, certain ruleset.
Instead setting it to
none
by default for.toggle
and then "resetting" it to the "active" value on a certain state, you can clear it only when it is not in that state.This can be done by setting
outline: none
with a selector like.toggle:not(:focus-visible)
.The code will explain better than I can:
This has a distinct benefit over the other approaches: users with browsers that do not support
:focus-visible
will get their browser’s default focus ring, instead of nothing.Another option would be to use a CSS custom property (AKA CSS variable) to hold the initial, default value. This would of course require that you can configure the the configuration system to set this custom property instead of
outline
directly.Then you could do something like this:
This defaults to using
none
, but will use the value of the--outline
var if it is defined.A possible downside to the basic approach is that everything that relied on the outline being set would now have to set it from
--outline
. Instead, you can set theoutline
property as well: "naive" elements will just use it, but any that need it can be customized (such as buttons).A last-ditch option: use
!important
in the*:focus-visible
rule, like so:This should be avoided if at all possible, because
!important
makes things complicated and harder to maintain and modify in the long run. But sometimes you gotta do what you gotta do (although it usually means there are flaws somewhere in the system).