WCAG 2.4.11: Focus Not Obscured (Minimum)
WCAG 2.4.11 Focus Not Obscured (Minimum) is a Level AA success criterion introduced in WCAG 2.1. It mandates that when a user interface component receives keyboard focus, the focus indicator must not be completely hidden by other author-created content. This criterion is crucial for users who rely on keyboard navigation to interact with web content, ensuring they can always visually track their position on a page.
Why Focus Not Obscured Matters for Accessibility
The ability to clearly see which element has keyboard focus is fundamental for accessible web interaction. When a focus indicator is obscured, users can become disoriented, frustrated, and unable to complete tasks. This criterion directly addresses the needs of several user groups:
- Keyboard Users: Individuals who navigate solely using a keyboard (e.g., via Tab, Shift+Tab, arrow keys) depend entirely on a visible focus indicator to understand where they are on the page and what element they are about to interact with. If the focus is hidden, they cannot effectively use the interface.
- Users with Low Vision: While they may not rely exclusively on a keyboard, users with low vision often use keyboard navigation alongside magnification tools. A partially or fully obscured focus indicator makes it significantly harder for them to locate and follow the focus, especially when content is magnified.
- Users with Cognitive Disabilities: Clear, consistent visual cues, such as a prominent focus indicator, are essential for users with certain cognitive disabilities. Hiding the focus can lead to confusion, increased cognitive load, and difficulty in understanding the page’s structure and interactive elements.
- Users of Screen Magnifiers: When content is magnified, a fixed element (like a sticky header) can easily obscure the focus indicator on a focused element, especially if that element is positioned at the top or bottom of the viewport.
Without a visible focus, users cannot confidently navigate forms, click buttons, activate links, or interact with widgets, leading to an inaccessible and unusable experience.
Understanding the Success Criterion 2.4.11
The official wording for WCAG 2.4.11 is:
2.4.11 Focus Not Obscured (Minimum): When user interface components receive keyboard focus, the focus indicator is not entirely hidden by author-created content.
This is a Level AA success criterion. Key aspects to understand include:
- “User interface components”: Refers to any interactive element that can receive keyboard focus, such as links, buttons, form fields, and custom widgets.
- “Keyboard focus”: The state an element enters when it is selected by keyboard navigation, typically indicated by a visual outline or style change.
- “Not entirely hidden”: This is the core of the criterion. It means that at least part of the focus indicator must be visible to the user. It does not mean the entire element must be visible, but the part that signals focus must be present.
- “Author-created content”: Refers to any content or styling provided by the website developer, including fixed headers, footers, sticky elements, modal dialogs, or other overlays. This criterion specifically addresses issues caused by design elements that obstruct the focus indicator.
This criterion complements WCAG 2.4.7 Focus Visible, which requires that any keyboard focus indicator be visible. WCAG 2.4.11 goes a step further by ensuring that even if a focus indicator exists, it isn’t rendered useless by being covered by other parts of the page’s design.
Practical Guidelines for Compliance
To ensure compliance with WCAG 2.4.11, developers and designers should consider the following:
-
Manage Fixed/Sticky Elements: Fixed headers, footers, and other sticky elements are common culprits for obscuring focus. Ensure these elements do not overlap and hide the focus indicator of interactive components when they receive focus.
- Use CSS
scroll-margin
: Applyscroll-margin-top
orscroll-margin-bottom
to scrollable container elements or directly to target elements. This CSS property reserves space for fixed headers/footers when the browser scrolls to a fragment identifier (#id
) or when an element is brought into view programmatically (e.g., usingscrollIntoView()
). - Adjust scroll position with JavaScript: If
scroll-margin
isn’t sufficient or for more complex scenarios, use JavaScript to scroll the page such that the focused element is fully visible and not under a fixed element. Calculate the offset needed based on the height of your fixed elements.
- Use CSS
-
Handle Modals and Overlays: When a modal dialog opens, ensure that focus is correctly managed within the modal and that no background content can receive focus underneath, nor should the modal itself hide focused elements when it first appears.
-
Test Thoroughly with Keyboard: Always test keyboard navigation across all interactive elements, paying close attention to areas near fixed or sticky components, at the top and bottom of the viewport, and within complex widgets.
-
Review Custom Focus Styles: While this criterion focuses on obstruction, remember that custom focus styles must also be sufficiently prominent and distinct from surrounding content to be easily perceived (per WCAG 2.4.7 and 2.4.11).
Examples of Correct and Incorrect Implementations
Incorrect Implementation: Fixed Header Obscuring Focus
In this common scenario, a fixed header with a high z-index
completely covers the focus indicator of elements located at the top of the viewport when they receive focus.
HTML
<header class="fixed-header">
<h1>My Website</h1>
<nav>
<a href="#">Home</a>
<a href="#">About</a>
</nav>
</header>
<main style="margin-top: 100px;">
<!-- Content to push down -->
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<a href="#link1" class="focusable-item">Link 1</a><br>
<a href="#link2" class="focusable-item">Link 2</a><br>
<a href="#link3" class="focusable-item">Link 3</a><br>
<a href="#link4" class="focusable-item">Link 4</a><br>
<!-- ... more content ... -->
<a href="#link50" class="focusable-item">Link 50</a>
</main>
CSS
.fixed-header {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 80px;
background-color: #333;
color: white;
padding: 10px 20px;
box-sizing: border-box;
z-index: 1000;
}
.focusable-item:focus {
outline: 3px solid orange;
background-color: lightblue;
}
/* When a focusable item is scrolled to, its outline is hidden by the fixed-header */
Problem
If a user navigates via keyboard (e.g., using Tab key) and an element like “Link 1” or “Link 2” receives focus near the top of the viewport, the .fixed-header
will likely cover its focus outline entirely, making it impossible for the user to see where their focus currently is.
Correct Implementation: Using scroll-margin-top
To prevent the fixed header from obscuring focus, we can use scroll-margin-top
on the focusable elements. This tells the browser to leave enough space at the top when scrolling to an an element’s fragment identifier or programmatically.
HTML
<header class="fixed-header">
<h1>My Website</h1>
<nav>
<a href="#">Home</a>
<a href="#">About</a>
</nav>
</header>
<main style="margin-top: 100px;">
<!-- Content to push down -->
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<a href="#link1" class="focusable-item" id="link1">Link 1</a><br>
<a href="#link2" class="focusable-item" id="link2">Link 2</a><br>
<a href="#link3" class="focusable-item" id="link3">Link 3</a><br>
<a href="#link4" class="focusable-item" id="link4">Link 4</a><br>
<!-- ... more content ... -->
<a href="#link50" class="focusable-item" id="link50">Link 50</a>
</main>
CSS
.fixed-header {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 80px;
background-color: #333;
color: white;
padding: 10px 20px;
box-sizing: border-box;
z-index: 1000;
}
.focusable-item {
/* Ensure focusable items have enough scroll margin when scrolled into view */
scroll-margin-top: 90px; /* Header height + a little extra padding */
}
.focusable-item:focus {
outline: 3px solid orange;
background-color: lightblue;
}
/* When a focusable item is scrolled into view (e.g., via Tab key or anchor link), the browser will ensure it appears below the fixed header due to scroll-margin-top. */
Explanation
By adding scroll-margin-top: 90px;
to .focusable-item
, we instruct the browser to always keep a 90-pixel buffer above these elements when they are scrolled into view (either by keyboard navigation or by direct links to their IDs), effectively preventing the 80px fixed header from obscuring their focus outline.
Correct Implementation: Using JavaScript for Dynamic Scrolling
For more complex scenarios, or when scroll-margin
isn’t fully supported or sufficient, JavaScript can be used to manually adjust the scroll position when an element receives focus.
HTML
<header class="fixed-header" id="site-header">
<h1>My Website</h1>
<nav>
<a href="#">Home</a>
<a href="#">About</a>
</nav>
</header>
<main style="margin-top: 100px;">
<!-- ... content ... -->
<p>More content to scroll past...</p>
<a href="#link1" class="focusable-item">Link 1</a><br>
<a href="#link2" class="focusable-item">Link 2</a><br>
<a href="#link3" class="focusable-item">Link 3</a><br>
<!-- ... more content ... -->
</main>
JavaScript
document.addEventListener('focusin', function(event) {
const focusedElement = event.target;
const fixedHeader = document.getElementById('site-header');
// Check if the focused element is not the fixed header itself or its children
if (fixedHeader && focusedElement && !fixedHeader.contains(focusedElement)) {
const headerHeight = fixedHeader.offsetHeight; // Get dynamic height
const focusedElementRect = focusedElement.getBoundingClientRect();
// If the focused element's top is within or above the fixed header's area
if (focusedElementRect.top < headerHeight) {
// Calculate the scroll amount needed to bring it below the header
const scrollY = window.scrollY || document.documentElement.scrollTop;
window.scrollTo({
top: scrollY + focusedElementRect.top - headerHeight - 10, // -10 for a little extra padding
behavior: 'smooth'
});
}
}
});
Explanation
This JavaScript snippet listens for the focusin
event (which bubbles up). When an element receives focus, it checks if that element is currently obscured by the fixed header. If it is, it calculates the necessary scroll position to bring the element into view just below the header, adding a small offset for padding. This approach is more robust for dynamically sized headers or complex layouts, and it specifically excludes elements within the header itself from being scrolled.
Best Practices and Common Pitfalls
Best Practices
- Design for Visibility: From the initial design phase, consider how fixed elements will interact with focused components. Design patterns that naturally avoid obstruction are ideal.
- Automate Offset Handling: Implement global CSS rules (like
scroll-margin
) or a JavaScript utility that automatically applies the necessary scroll offset for fixed headers/footers to all focusable elements. - Test with Real Users: Beyond automated checks, conduct usability testing with keyboard-only users to catch nuanced issues related to focus visibility.
- Cross-Browser and Device Testing: Ensure your solution works consistently across different browsers and on various screen sizes, as fixed elements can behave differently.
- Leverage ARIA and Semantic HTML: While not directly addressing 2.4.11, using correct semantic HTML and ARIA roles helps ensure that interactive elements are correctly identified by assistive technologies, which often works in tandem with visual focus.
Common Pitfalls
- Neglecting Fixed Headers/Footers: This is by far the most common cause of non-compliance. Developers often overlook the interaction between sticky/fixed elements and keyboard focus.
- Overly Subtle Focus Styles: While WCAG 2.4.11 is about obstruction, it’s worth noting that a subtle focus style is easily obscured even by minimal overlap. Ensure your focus styles are robust (WCAG 2.4.7 and 2.4.11 related).
- Overlaying Modals/Popups: When a modal or popup appears, if the underlying content can still receive focus and that focus is hidden by the modal, it’s a violation. Ensure focus is trapped within the modal and background content is inert.
- Dynamic Content Changes: If content dynamically loads or changes layout, it can inadvertently push focused elements under fixed headers or other elements. Ensure focus management is re-evaluated after significant layout changes.
- Ignoring Zoom Levels: Users might zoom in, which can change the layout and make fixed elements occupy a larger portion of the viewport, increasing the likelihood of focus being obscured. Test at various zoom levels.
Conclusion
WCAG 2.4.11 Focus Not Obscured (Minimum) is a critical criterion for creating accessible web experiences, particularly for keyboard users. By proactively managing the interaction between fixed/sticky elements and focus indicators, developers can ensure that all users have a clear and unambiguous way to interact with web content, leading to a more inclusive and usable internet.