Focus Styling: From :focus to :focus-visible
Initially, browsers universally applied focus styles via the :focus
pseudo-class to all focusable elements, typically as a focus ring. This default user-agent style ensured every link and button displayed a focus ring when focused. Developers often overrode this default for visual consistency.
However, always-visible focus rings on every element were considered visually distracting and detrimental to UX. Users found the constant focus indicators overwhelming.
Modern browsers now selectively apply focus rings based on heuristics. Focus styles are crucial for keyboard navigation and programmatic focus management (JavaScript). However, when users directly interact using mouse or touch, focus rings are often redundant. Form elements remain a key exception where clear focus indication remains important.
The :focus-visible
pseudo-class addresses this by respecting the browser's intelligent focus indication while allowing style customization. This provides a more nuanced approach, but :focus
styles remain necessary for older browser compatibility. However you can get away with just providing :focus-visible
styles if you can absolutely guarantee that all your users are on a device that supports :focus-visible
, otherwise you will need to use a polyfill or a CSS fallback method.
For broad browser support, consider these fallback strategies:
Method 1: @supports
Feature Query
CSS
*:focus { /* Default focus styles */ }
@supports selector(:focus-visible) {
*:focus { /* Undo default styles in modern browsers */ }
*:focus-visible { /* Reapply for :focus-visible */ }
}
Method 2: :not(:focus-visible)
Fallback
CSS
*:focus { /* Default focus styles */ }
*:focus:not(:focus-visible) { /* Undo default styles in :focus-visible browsers */ }
*:focus-visible { /* Styles for :focus-visible browsers */ }
While less explicit, you could also use:
CSS
*:focus-visible { /* Focus styles for :focus-visible */ }
@supports not selector(:focus-visible) {
*:focus { /* Focus styles for older browsers */ }
}
Methods 1 & 2 are clearer in demonstrating the fallback approach, explicitly showing default :focus
styles being refined for :focus-visible
browsers.