:focus<\/code> pseudo-class:<\/p>\n\n\n\n.next-image-button:focus {\n outline: none;\n}<\/code><\/pre>\n\n\n\nNow your button looks great when it is in focus, but what happens when a user tabs to your button without a mouse but a keyboard instead? They can’t see where they’ve tabbed! That’s a problem because now there’s no way to tell which button is focused for keyboard actions:<\/p>\n\n\n\nOne of these is focused, but you can’t see it!<\/figcaption><\/figure>\n\n\n\nIs there a way to remove the blue focus outline but still show a focus that’s more in line with the site design? Sure, you can have your cake and eat it too, thanks to :focus-visible<\/code>!<\/p>\n\n\n\n:focus-visible<\/code> only applies when you actually want<\/em> a visual indicator to help the user see where the focus is. In other words, it can’t hide the outline like :focus<\/code> can. (Well, it could<\/em> by blending it into the design, but whatever.) The two have to be used together in that sense. Let’s add one to our button:<\/p>\n\n\n\n.next-image-button:focus {\n outline: none;\n}\n.next-image-button:focus-visible {\n outline: 3px solid blanchedalmond; \/* That'll show 'em *\/\n}<\/code><\/pre>\n\n\n\nNow, when the keyboard is used to tab to the button, there will be a visual indication of the focus:<\/p>\n\n\n\n:focus-visible<\/code> makes focus visible!<\/figcaption><\/figure>\n\n\nHow do browsers determine when something is :focus-visible?<\/h3>\n\n\n
Browsers are given a bit of leeway to determine when this pseudo-selector should be applied to a given element using their own heuristics. First, let’s look at the CSS4 working draft, and then we’ll try to break it down. From the specifications<\/a>:<\/p>\n\n\n\n\n- If a user has expressed a preference (such as via a system preference or a browser setting) to always see a visible focus indicator, the user agent should honor this by having :focus-visible always match on the active element, regardless of any other factors. (Another option may be for the user agent to show its own focus indicator regardless of author styles.)<\/li>\n
- Any element which supports keyboard input (such as an input element, or any other element which may trigger a virtual keyboard to be shown on focus if a physical keyboard is not present) should always match :focus-visible when focused.<\/li>\n
- If the user interacts with the page via the keyboard, the currently focused element should match :focus-visible (i.e. keyboard usage may change whether this pseudo-class matches even if it doesn\u2019t affect :focus).<\/li>\n
- If the user interacts with the page via a pointing device, such that the focus is moved to a new element which does not support user input, the newly focused element should not match :focus-visible.<\/li>\n
- If the active element matches :focus-visible, and a script causes focus to move elsewhere, the newly focused element should match :focus-visible.<\/li>\n
- Conversely, if the active element does not match :focus-visible, and a script causes focus to move elsewhere, the newly focused element should not match :focus-visible.<\/li>\n<\/ul><\/blockquote>\n\n\n\n
If that’s a little abstract, here’s an interpretation:<\/p>\n\n\n\nSituation<\/th> | Does :focus-visible apply?<\/th><\/tr> |
---|
The user says they always want the focus to be visible via a setting<\/td> | Yes<\/td><\/tr> |
An element needs a keyboard to function (like text <inputs>)<\/td> | Yes<\/td><\/tr> |
The user is navigating with a keyboard<\/td> | Yes<\/td><\/tr> |
The user is navigating with a pointing device (like a mouse or finger on a touchscreen)<\/td> | No<\/td><\/tr> |
A script causes focus to move from a :focus-visible<\/code> element to another element<\/td>Yes<\/td><\/tr> | A script causes focus to move from a non-:focus-visible<\/code> element to another element<\/td>No<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n It bears repeating: These are guidelines, and browsers will be able to make their own determination about what is selected by :focus-visible<\/code>. We can expect that the obvious case of keyboard navigation will be handled in a predictable way, but the browsers have the ability to make the determination themselves, like any other feature.<\/p>\n\n\n\n | | |