Making a sticky header meet WCAG 2.2 guidelines
As part of my recent work I’ve had the opportunity to investigate and work on making a website adhere to the latest WCAG 2.2 standard.
In this post I will focus on the focus not obscured criterion (2.4.11) particularly with regards to a sticky navigation obscuring the users focus.
What’s the issue
When navigating a website with a mouse we use the mouse cursor as an indicator of where we are on the page.
However, there are tonnes of people that use other methods, such as keyboard, switch devices or voice control, with this method of navigating a webpage a focus indicator such as; colour, outline or shading are used to indicate where a user is on the page.
This new WCAG 2.2 criterion (2.4.11) has been introduced to ensure when a component has focus, part or all of it is visible, this is depending on whether you are aiming for AA or AAA. Makes total sense really.
WCAG Criterion 2.4.11 has a minimum (AA) and maximum (AAA)
- AA - When a component has focus, part of it is visible.
- AAA - When a component has focus, it is fully visible
A sticky heading component
A common design pattern on lots of sites is to have a sticky header for ease of navigation. However, this may cause issues with accessibility associated with 2.4.11. In the following examples I will show why.
First let's use this wireframe as an example of a site with a sticky header, the page has several links and buttons which all have accessible focus states coded onto them.
The user has navigated through all the content and has decided to go back up the page (shift + tab) to go back up the page. However, they now can’t see their focus indicator? This is because the sticky header is obscuring the visibility of the focussed link. This now fails to indicate to the user where their current focus is on the website.
How can we fix this issue?
A nice fix for this would be to utilise the css scroll-padding property. We can use this to offset the position on the screen of the focused element.
Please check out this codepen to see how I resolved the issue. I basically store the fixed header height as a CSS var, and offset the scroll-padding-top property by it when a link is focused.
This ensures that the focused link is always visible when the header is stuck.
Outside of the demo where I’m adding a class to the body to enable it you could simply add it to your css with a HTML selector similar to:
html { scroll-padding-bottom:var(--scroll-padding) }
Things worth mentioning
If your sticky header has a level of opacity and you can see the focus indicator, you would test the visual contrast ratio. Ideally the focus indicator would have a contrast ratio of at least 3:1. https://www.w3.org/TR/WCAG22/#focus-appearance