WCAG Success Criteria · Level AAA

WCAG 2.4.12: Focus Not Obscured (Enhanced)

WCAG 2.4.12 requires that when a UI component receives keyboard focus, no part of that component is hidden by author-created content — the focused element must be fully visible. This enhanced (AAA) criterion eliminates the partial-visibility allowance of its AA counterpart, ensuring keyboard users always see exactly where focus is.

  • Level AAA
  • Wcag
  • Wcag 2 2 aaa
  • Operable
  • Accessibility

What This Rule Means

WCAG 2.4.12 — Focus Not Obscured (Enhanced) — is the AAA counterpart to WCAG 2.4.11 (Focus Not Obscured, AA). Where the AA criterion permits a focused component to be partially visible, the AAA criterion demands that the focused component is entirely visible — no part of it may be hidden by author-created content when it receives keyboard focus.

In practical terms, this means that when a user tabs to an interactive element such as a link, button, form field, or custom widget, the complete bounding area of that element must be unobscured by any sticky header, fixed footer, modal overlay, cookie banner, chat widget, or any other content the author has placed on the page. The rule targets author-created content specifically; the W3C makes an explicit exception for content that the user themselves has moved to obscure the focus indicator — for example, a floating panel that the user dragged in front of the focused element. In that case, the author is not responsible.

A pass under 2.4.12 requires that upon receiving focus, the entire focused component is visible within the viewport and is not covered by any sticky, fixed, or absolutely-positioned element that the page author controls. A fail occurs when any portion of the focused element's visible boundary is hidden behind such overlays — even a single pixel of the focus ring or the component itself being clipped counts as a failure at the AAA level.

It is important to understand what 2.4.12 does not cover. It does not mandate a particular focus indicator style (that is addressed by 2.4.11 and 2.4.7). It does not require that focus indicators have a minimum contrast ratio (covered by 2.4.13). It specifically addresses the spatial relationship between the focused element and other content on the page — the layering problem that arises most commonly from fixed and sticky positioning in CSS.

Affected HTML elements include any focusable or tabbable element: <a>, <button>, <input>, <select>, <textarea>, <details>, elements with tabindex, and custom interactive widgets built with ARIA roles. The criterion applies across all browsing contexts including iframes, dialogs, and single-page application route transitions.

Why It Matters

Keyboard navigation is a primary access method for a wide range of users. People with motor impairments — including those living with conditions such as ALS, multiple sclerosis, cerebral palsy, or repetitive strain injury — rely entirely on the keyboard or switch access devices rather than a mouse. Blind and low-vision users operating screen readers also navigate by keyboard, and although their assistive technology announces focus position audibly, sighted keyboard users depend entirely on the visual focus indicator to orient themselves on the page.

When the focused element is obscured, even partially, these users face a frustrating and potentially disorienting experience: the page appears to offer no focused element at all, or the user must guess where they are in the document. At the AA level (2.4.11), partial visibility is tolerated — at least some of the component is visible, providing a cue. The AAA criterion eliminates this compromise entirely, recognising that even a partially hidden focus indicator can be missed by users with reduced contrast sensitivity, tunnel vision, or cognitive conditions that make scanning a screen more demanding.

Consider a concrete scenario: a Turkish e-commerce website uses a fixed navigation bar 80px tall at the top of the viewport and a sticky cookie consent banner 60px tall at the bottom. A user pressing Tab to navigate through product cards may find that the focused card's top or bottom edge — including its focus ring — slides beneath one of these fixed surfaces. Under WCAG 2.4.11 (AA), if any part of the card is still visible the site passes. Under 2.4.12 (AAA), the entire card must be fully visible. This distinction is meaningful: a partially hidden button label combined with a partially hidden focus ring can make it genuinely impossible for a low-vision user to determine which element is active or what action it will perform.

According to the World Health Organization, approximately 2.2 billion people globally have some form of vision impairment, and motor disabilities affect hundreds of millions more. Keyboard accessibility improvements benefit not only these groups but also power users who prefer keyboard navigation for speed, users on devices without a pointing device, and users in situations where fine motor control is temporarily impaired.

Beyond disability access, fully visible focus improves general usability and reduces support costs. When all users — including those without disabilities — can clearly track focus position, form completion rates improve and error rates decrease. For sites targeting the Turkish market, demonstrating AAA conformance signals a mature accessibility programme and builds trust with both users and institutional procurement teams.

WCAG 2.4.12 is classified as requiring manual testing and is part of the WCAG 2.2 additions. There is no fully automated axe-core rule that can reliably detect this violation, and understanding why is important for teams building their testing pipelines.

  • Manual inspection — focus-not-obscured-enhanced (no automated rule): Automated accessibility scanners such as axe-core operate on the static DOM or a snapshot of rendered state. Detecting whether a focused element is obscured requires: (1) simulating keyboard focus on every interactive element in sequence, (2) computing the element's bounding rectangle after focus-induced scroll, (3) identifying all fixed and sticky-positioned elements and their bounding rectangles, and (4) testing for geometric overlap. While partial automation is theoretically possible, the dynamic nature of scroll behaviour, CSS scroll-padding, smooth scrolling, and JavaScript-driven focus management makes this highly unreliable in practice. A focused element that is perfectly visible at one viewport size may be fully obscured at another. axe-core flags this criterion as requiring human judgement and marks findings as "needs review" rather than automatic violations. Testers must manually tab through every interactive element and visually confirm full visibility at each relevant viewport width.
  • scrollable-region-focusable (axe rule): While not directly mapped to 2.4.12, this axe rule flags elements inside scrollable regions that are focusable but may not scroll into view correctly. It is a related signal that indicates scroll-management issues which could cause focus to be obscured by sticky headers or footers — the most common failure mode for 2.4.12.

Because automated tools cannot reliably catch 2.4.12 violations, organisations must build manual keyboard walkthroughs into their QA process, ideally at multiple viewport sizes and with all persistent UI layers (navigation bars, chat widgets, cookie banners, GDPR notices) active.

How to Test

  1. Automated baseline scan: Run axe DevTools or Lighthouse against the page to identify any related issues such as scrollable-region-focusable violations or CSS overflow problems. These findings, while not direct 2.4.12 violations, indicate areas of the page most likely to cause focus-obscuring issues. In axe DevTools, filter by WCAG 2.2 criteria and review any "needs review" items related to focus visibility.
  2. Identify all persistent overlaid content: Before keyboard testing, visually catalogue every element with position: fixed or position: sticky on the page — typically navigation bars, cookie banners, chat widgets, floating action buttons, and footer toolbars. Note their heights and positions so you know which zones of the viewport they occupy.
  3. Keyboard navigation walkthrough: Starting from the top of the page (or after dismissing any initial modal), press Tab repeatedly to move focus through every interactive element. At each focus stop, verify that the entire focused element — including its visible focus indicator (outline or ring) — is fully within the unobscured viewport area. Do not accept partial visibility. If any portion of the element or its focus ring disappears behind a fixed element, record this as a 2.4.12 failure.
  4. Reverse navigation: Repeat the walkthrough using Shift+Tab to navigate backwards. Fixed footers are often missed in forward-only tests but may obscure elements when tabbing in reverse.
  5. Screen reader testing with NVDA + Firefox: Open NVDA, launch Firefox, and navigate using Tab. When NVDA announces focus on an element, visually confirm the element is fully visible. NVDA's focus mode does not automatically scroll elements clear of fixed layers, so violations may differ from browser-native behaviour.
  6. Screen reader testing with VoiceOver + Safari (macOS/iOS): Enable VoiceOver and use Tab (or swipe on iOS) to navigate. Safari's scroll management sometimes differs from Chromium's, potentially exposing obscured focus states not seen in Chrome.
  7. Responsive viewport testing: Repeat the keyboard walkthrough at common breakpoints — 320px, 768px, 1024px, and 1440px wide. Sticky elements often become taller or reposition at different breakpoints, changing which zones are at risk.
  8. Test after user interactions: Open dropdown menus, expand accordions, trigger modals, and navigate to new routes in single-page applications. After each state change, resume Tab navigation and re-verify full focus visibility, since dynamic content often introduces new fixed overlays.

How to Fix

Sticky Header Obscuring Focused Links — Incorrect

<!-- Fixed header with no scroll compensation -->
<header style='position:fixed; top:0; height:80px; background:#fff; width:100%;'>
  <nav>...</nav>
</header>

<main>
  <!-- When Tab reaches this link near the top of main, the header covers it -->
  <a href='/products'>View all products</a>
</main>

Sticky Header Obscuring Focused Links — Correct

<!-- scroll-padding-top ensures focused elements scroll clear of the fixed header -->
<style>
  html {
    /* Match this value to the height of your fixed header */
    scroll-padding-top: 88px; /* 80px header + 8px breathing room */
  }
</style>

<header style='position:fixed; top:0; height:80px; background:#fff; width:100%;'>
  <nav>...</nav>
</header>

<main style='margin-top:80px;'>
  <!-- Focus now scrolls the element fully clear of the header -->
  <a href='/products'>View all products</a>
</main>

Cookie Banner Covering Bottom-of-Viewport Interactive Elements — Incorrect

<!-- Cookie banner fixed to the bottom, no scroll compensation -->
<div id='cookie-banner' style='position:fixed; bottom:0; height:72px; width:100%; background:#222;'>
  <button>Accept All</button>
  <button>Manage Preferences</button>
</div>

<footer>
  <!-- These links at the bottom of the page get covered by the cookie banner -->
  <a href='/privacy'>Privacy Policy</a>
  <a href='/terms'>Terms of Service</a>
</footer>

Cookie Banner Covering Bottom-of-Viewport Interactive Elements — Correct

<!-- Add scroll-padding-bottom and body padding to compensate for the banner height -->
<style>
  html {
    scroll-padding-bottom: 80px; /* 72px banner + 8px breathing room */
  }
  body {
    padding-bottom: 80px; /* Prevent content from being permanently under the banner */
  }
</style>

<div id='cookie-banner' style='position:fixed; bottom:0; height:72px; width:100%; background:#222;'>
  <button>Accept All</button>
  <button>Manage Preferences</button>
</div>

<footer>
  <!-- Links now scroll fully into the unobscured viewport area -->
  <a href='/privacy'>Privacy Policy</a>
  <a href='/terms'>Terms of Service</a>
</footer>

JavaScript Focus Management Not Accounting for Fixed Layers — Incorrect

<!-- SPA route change: focus moved to heading but scrollIntoView ignores header -->
<script>
function navigateTo(section) {
  const heading = document.querySelector('#' + section + ' h2');
  heading.setAttribute('tabindex', '-1');
  heading.focus();
  // scrollIntoView with no offset — heading scrolls behind fixed header
  heading.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
</script>

JavaScript Focus Management Not Accounting for Fixed Layers — Correct

<!-- Use scroll-margin-top on the target element, or manually offset scrollY -->
<style>
  .focus-target {
    /* scroll-margin-top offsets this element's scroll position from the top */
    scroll-margin-top: 96px;
  }
</style>

<script>
function navigateTo(section) {
  const heading = document.querySelector('#' + section + ' h2');
  heading.setAttribute('tabindex', '-1');
  // scroll-margin-top on the element handles the visual offset automatically
  heading.classList.add('focus-target');
  heading.focus();
  // scrollIntoView now respects scroll-margin-top, clearing the fixed header
  heading.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
</script>

Common Mistakes

  • Setting scroll-padding-top on body instead of html: The CSS scroll-padding property must be applied to the scroll container. For full-page scroll, the scroll container is the html element, not body. Applying it to body has no effect in most browsers and is one of the most common implementation errors.
  • Hardcoding a fixed pixel value for scroll-padding-top that does not match the actual header height at all breakpoints: When the header collapses to a smaller height on mobile or expands to include a secondary nav bar on desktop, the static offset becomes wrong. Use CSS custom properties updated via JavaScript or use calc() with relative units to keep the value in sync.
  • Forgetting scroll-margin-top on in-page anchor targets: Even when the global scroll-padding-top is correct for Tab navigation, anchor link targets that receive programmatic focus (e.g., skip links, hash navigation in SPAs) may still land under the header unless scroll-margin-top is also set on those specific elements.
  • Dismissing the cookie banner without re-testing: Many teams test keyboard navigation only after accepting the cookie banner. Because the banner occupies the bottom of the viewport, bottom-anchored focusable elements may be obscured only while the banner is active. Always test with all persistent UI layers in their fully displayed state.
  • Testing only at one viewport width: Sticky elements often change height, become visible, or disappear entirely at different breakpoints. A failure at 375px may not appear at 1440px, and vice versa. Testing at only one size misses a substantial proportion of real-world violations.
  • Using overflow: hidden on a parent container to clip focus indicators: When a card component or container has overflow: hidden, the browser-default focus outline on child elements is clipped at the container boundary. This can make focus appear fully visible in DevTools element inspection while being visually cut off for the user.
  • Assuming screen readers handle scroll automatically so visual testing is unnecessary: While screen readers announce the focused element audibly, sighted keyboard users — including those using screen magnification tools — rely entirely on visual position. A visually obscured focus state is a real failure regardless of screen reader behaviour.
  • Not testing modal dialogs and drawer overlays: When a modal opens and focus is moved inside it, the backdrop or the modal chrome itself may obscure the first focused element inside the dialog. This is especially common in drawer-style panels that animate in from the side or bottom.
  • Ignoring third-party widgets such as live chat bubbles and interstitial ad banners: Floating chat widgets (e.g., Intercom, Zendesk) and fixed promotional banners injected by tag managers are author-created content and fall within scope of this criterion. Teams often overlook these because they are managed outside the main codebase.
  • Relying solely on automated accessibility scans and closing the ticket: Because 2.4.12 requires manual testing, a clean axe-core scan does not confirm conformance. Closing accessibility tickets based on automated results alone will consistently miss this criterion.

Relation to Turkey's Accessibility Regulations

Turkey's Presidential Circular 2025/10, published in the Official Gazette No. 32933 on 21 June 2025, establishes binding web and mobile accessibility requirements for a broad range of entities operating in Turkey. The circular adopts WCAG 2.1 Level AA as its baseline conformance standard, meaning that WCAG 2.4.12 — as a WCAG 2.2 AAA criterion — is not directly mandated under the current regulation. However, its relationship to Turkey's accessibility framework is significant for several reasons.

The entities covered by Presidential Circular 2025/10 include public institutions and government bodies at all levels, e-commerce platforms, banks and financial service providers, hospitals and healthcare organisations, telecommunications companies with 200,000 or more subscribers, travel agencies, private transport companies, and private schools that have been authorised by the Ministry of National Education (MoNE). For all of these organisations, achieving WCAG 2.1 AA compliance is a legal obligation, and the circular is expected to be enforced through audit mechanisms administered by relevant supervisory bodies.

While AAA conformance is not required by the circular, organisations in regulated sectors have strong practical reasons to pursue WCAG 2.4.12 compliance. First, the Turkish regulatory landscape is evolving: the circular represents a significant escalation of accessibility enforcement compared to prior guidance, and future revisions may adopt WCAG 2.2 or raise the conformance level. Organisations that build AAA practices now will be better positioned for regulatory changes. Second, public procurement processes and EU market access increasingly favour suppliers who can demonstrate enhanced accessibility programmes, and AAA conformance documentation provides a competitive differentiator.

Third, and most directly relevant to WCAG 2.4.12, the criterion addresses a failure mode that disproportionately affects users of assistive technology in Turkey — a population estimated at several million people when motor, visual, and cognitive disabilities are counted together. Banks, hospitals, and e-government portals that rely heavily on fixed navigation chrome and persistent notification layers are precisely the sites where focus-obscuring failures are most common. Investing in full WCAG 2.4.12 compliance demonstrates a genuine commitment to serving all users, aligns with the spirit of the presidential circular even where the letter does not yet require it, and reduces legal and reputational risk as Turkish enforcement matures.

For organisations using the Accsible overlay SDK, the platform provides tooling to audit keyboard focus paths and identify sticky-positioning conflicts, supporting both the mandatory AA requirements of Presidential Circular 2025/10 and voluntary AAA enhancements such as WCAG 2.4.12.