Level AAA

Any sticky header, footer, cookie banner, or chat widget that overlaps a focused element by even one pixel fails this Level AAA criterion -- the strict counterpart to 2.4.11.

2.4.12 Focus Not Obscured (Enhanced)

In Plain Language

[2.4.12 Focus Not Obscured (Enhanced)] is new in WCAG 2.2 at Level AAA[1]. When a user interface component receives keyboard focus, no part of that component may be hidden by author-created content -- sticky headers, fixed footers, cookie banners, non-modal dialogs, and chat widgets must not overlap the focused element at all.

2.4.12 is the strict counterpart to 2.4.11 Focus Not Obscured (Minimum)[2]. 2.4.11 (Level AA) passes as long as some part of the focused element remains visible. 2.4.12 (Level AAA) fails on a single pixel of overlap with author content.

Why It Matters

  • Partial occlusion hides load-bearing context. A button whose label reads "Delete" when the word "permanently" is clipped by a sticky footer invites destructive mis-activation.
  • Screen magnifier users render a narrow viewport at high zoom. A sticky header that clips the top of a focused field can leave the magnified region showing only the overlay, stripping the focus indicator and the accessible name from the user's view at once.
  • Sighted keyboard users track the focus ring as a positional anchor. When the ring is partially covered, the user loses the pixel-level confirmation that 2.4.7 Focus Visible exists to provide -- which is why 2.4.12 treats the entire component, not only the indicator, as off-limits to overlap[1].
  • Semi-opaque overlays are explicitly out of scope for 2.4.12 (they are treated under contrast criteria), but any opaque content on top of the focused component is a failure[1].

Examples

Do: Generous scroll padding keeps entire focus ring visible
Sticky Navigation Bar

Tab through these links -- the entire focus ring stays visible:

First link
Second link
Third link

✔ scroll-padding-top accounts for both sticky header height and outline-offset so nothing is obscured

/* scroll-padding-top MUST equal the full height of every sticky overlay
   plus the focus ring outline-width and outline-offset. For 2.4.12, any
   residual overlap is a failure -- budget generously. */
html {
  scroll-padding-top: 5rem; /* 3.5rem header + 0.25rem outline + 0.5rem buffer */
}

header {
  position: sticky;
  top: 0;
  height: 3.5rem;
  z-index: 10;
}

:focus-visible {
  scroll-margin-top: 5rem; /* matches scroll-padding-top on the container */
  outline: 3px solid rgba(26, 107, 90, 0.5);
  outline-offset: 4px;
}
Don't: Focus ring partially clipped by a sticky footer

Tab to the link below -- its focus ring is clipped by the footer:

✘ The focus ring is partially covered by the fixed footer -- passes 2.4.11 but fails 2.4.12

Cookie consent banner clipping the focus ring

How to Fix It

  1. Match scroll-padding to the full overlay height. 2.4.11 tolerates partial visibility, so scroll-padding-top only has to clear enough of a sticky header to leave something showing. 2.4.12 requires the padding to equal the sticky element's full height plus outline-width and outline-offset. Compute it from the real rendered height, not a guess.
  2. Set scroll-margin-top / scroll-margin-bottom on focusable elements. When the browser scrolls a focused element into view, it honours scroll-margin on the target. Apply it via :focus-visible (or a global selector on interactive elements) so programmatic focus moves land outside every sticky region, not just the one closest to the viewport edge.
  3. Dismiss, collapse, or exclude overlays from the focus path. Cookie banners and chat widgets that auto-collapse on first Tab keep the sticky region small enough for the padding math to stay valid. If an overlay cannot be dismissed, its height must be added to scroll-padding for the duration it is on screen.
  4. Recompute on viewport and layout change. Sticky-element heights change with responsive breakpoints, font-size preferences, and dismissible banners. Use a ResizeObserver on each sticky container and write its current height to a CSS custom property that scroll-padding consumes.
  5. Audit with the keyboard, not just the mouse. Tab through every interactive element at the breakpoints you ship (mobile, tablet, desktop) and at 200% zoom. Any focus ring or component edge clipped by a sticky region is a 2.4.12 failure even if 2.4.11 would pass.
  6. Check z-index stacking. An overlay with a higher z-index than the focused element's nearest stacking context will paint over it regardless of scroll math. Keep sticky chrome in a dedicated stacking layer and verify no author content can float above the content region where focus lives.

References

  1. [1] W3C (2023). Understanding Success Criterion 2.4.12: Focus Not Obscured (Enhanced). W3C, Accessed 2026-04-07. https://www.w3.org/WAI/WCAG22/Understanding/focus-not-obscured-enhanced.html
  2. [2] W3C (2023). Understanding Success Criterion 2.4.11: Focus Not Obscured (Minimum). W3C, Accessed 2026-04-07. https://www.w3.org/WAI/WCAG22/Understanding/focus-not-obscured-minimum.html