Series: 11ty Theme
tl;dr: WCAG is now encouraging a certain focus indicator style, with two colours appearing outside the normal size of the item.
Series Description: However many years later, I have actually done something resembling completing the design of this site using eleventy aka 11ty! I'm sure there are still more things I'll decide to change later, but the general idea I'm pretty happy with. This series describes some of the main challenges I faced. You can navigate other posts in the series using the list of links in the sidebar.
The Web Content and Accessibility Guidelines has some documentation here that addresses making focus indicators more consistent and always easy to see.
One approach is to have the same focus style on the entire site. This might cause a problem in that the style will show up better in some contexts than in others, e.g. if it is a dark border, that won't show up as well in the menu with a dark background as it does in the white background main area.
Another approach is to have different styles depending on where it appears. This takes a bit more CSS work to define each possible combination, but on a lot of sites it is definitely doable. I have usually taken this approach. It does have a problem, too, though: it isn't as obvious that it is indicating focus when it is a different effect depending on where it appears. A user could start tabbing through the menu, seeing one effect, then get to the main content and suddenly it is a different effect. It might not be obvious that it is indicating the same thing - focus - because the user has started to think of one style as focus and now it is something else.
The solution is to have two colours, one light and one dark, across the entire site. That way, at least one of the two will stand out against any backdrop.
Version 1: Box Shadow
Here is the relatively simple version I initially decided to implement on this site:
:root {
--syntax-tab-size: 2;
--ring-inner-width: 2px;
--ring-gap: 2px;
--ring-outer-width: 2px;
}
@media (prefers-color-scheme: dark) {
:root {
--background-color: var(--near-black);
--focus-bg: var(--near-black);
--border-color: var(--white);
--button-border: var(--white);
--color: var(--white);
--color-link: var(--white);
--color-link-active: var(--grey);
--ring-inner-color: var(--white);
--ring-outer-color: var(--red);
}
}
@media (prefers-color-scheme: light) {
:root {
--focus-bg: var(--white);
--ring-inner-color: var(--blue);
--ring-outer-color: var(--red);
}
}
a:focus-visible,
a:hover,
button:focus-visible,
button:hover,
summary:focus-visible,
summary:hover,
input:focus-visible,
input:hover {
text-decoration: none;
box-shadow:
0 0 0 var(--ring-inner-width) var(--ring-inner-color),
0 0 0 calc(var(--ring-inner-width) + var(--ring-gap)) var(--focus-bg),
0 0 0
calc(var(--ring-inner-width) + var(--ring-gap) + var(--ring-outer-width))
var(--ring-outer-color);
}
The good thing about this is being able to define one rule with two colours - the stated goal here - that applies to the entire site.
Unfortunately, I soon discovered that this causes other issues, specifically when a link with multiple words spans across multiple lines. Firefox in particular would show the lines in between item. That could be alleviated by adding display: inline-block but then the whole link can shift to a new line instead, which is much more jarring.
Back to Outline
After that, I chose to go back to outline. Outline cannot do two coloured rings, though; the best it can do is an offset (transparent, not a colour) and then the coloured ring. It is much more reliable in terms of avoiding layout shift, though. It's not one rule for the entire site. It's one rule for the header and footer, one rule for the body (with variations based on whether in light or dark mode). It's not meeting the full goal here. It might not be quite as flexible for if new background colours are added that would warrant an exception to these general rules. But it's the best I could do right now.
a:focus-visible,
a:hover,
button:focus-visible,
button:hover,
summary:focus-visible,
summary:hover,
input:focus-visible,
input:hover {
text-decoration: none;
outline: 2px solid var(--ring-outer-color);
outline-offset: 2px;
}
header a:is(:focus, :focus-visible, :hover),
header button:is(:focus, :focus-visible, :hover),
header summary:is(:focus, :focus-visible, :hover),
header input:is(:focus, :focus-visible, :hover) {
outline: 2px solid var(--white);
}
footer a:is(:focus, :focus-visible, :hover),
footer button:is(:focus, :focus-visible, :hover),
footer summary:is(:focus, :focus-visible, :hover),
footer input:is(:focus, :focus-visible, :hover) {
outline: 2px solid var(--white);
}
This also can have some extra overlapping lines in Firefox in particular, but most of the time it is a clean line down the middle, still entirely readable.
Hover and Focus?
The other interesting question I explored here is whether focus and hover should have the same effect or a different one. On the one hand, if they were different, it does make it more clear if you are hovering or focus. On the other hand, for the most part, this doesn't really matter because you are probably only navigating either by keyboard or mouse, not both at the same time (other than when testing those effects maybe). Also, having the same effect for both has the benefits of less code to maintain and more consistency in experience. So, I decided to opt for having the same effect for both, which is now what I have always done in the past but seemed like the better decision.
Previous: Email: Proton
Next: Email: Proton Part 2