Fixing Focus Visibility Issues with Sticky Navigation in Webflow

Share this post

Webflow Scroll

If you’ve ever built a Table of Contents, anchor links, or in-page navigation in Webflow and thought:

“Why is focus technically moving, but users can’t actually see it?”

You’re not alone.

This is one of the most frustrating, subtle, and high-impact accessibility issues in Webflow projects, especially when a site uses a sticky or animated navigation header. It looks like everything is working… until you test it properly with a keyboard or screen reader.

This post breaks down:

  • The exact problem we ran into
  • Why common fixes don’t work in Webflow
  • The Webflow-specific pattern that finally solved it
  • A reusable script you can keep in your toolkit

The Problem: Focus Moves, but Content Is Hidden

Here’s the scenario:

  • A page includes a Table of Contents with anchor links
  • Clicking or activating a TOC link scrolls the page
  • Focus is programmatically moved to the target heading
  • BUT… the heading ends up hidden behind the navigation bar

This is especially common when:

  • The nav is sticky or animated
  • The nav hides on scroll down and reappears on scroll up
  • Webflow Interactions or custom scroll scripts are involved

From a keyboard or screen reader user’s perspective:

  • Focus does move
  • But the focused content is not visible
  • The page feels broken and disorienting

This is a real accessibility failure, not a cosmetic issue.

Why Common Solutions Fail in Webflow

Before finding the fix, we tried all the “standard” approaches you’ll see recommended online.

scroll-margin-top

This only works with native browser anchor scrolling.
If you prevent default behavior and use window.scrollTo() or scrollIntoView(), the browser never applies the margin.

scrollIntoView({ block: "start" })

This doesn’t account for animated headers. The nav often reappears after the scroll completes, covering the focused content again.

❌ Focusing immediately after scrolling

In Webflow, focus can trigger layout reflows. When combined with a nav that animates on scroll direction, this creates a timing race you will lose.

In short:
Webflow’s navigation behavior is a third actor in the system, and most scripts don’t account for it.

The Breakthrough: Focus First, Scroll Last

The key insight was this:

In Webflow, you must allow the navigation to react before you finalize scroll positioning.

The pattern that works is:

  1. Move focus to the target element first
  2. Allow Webflow’s nav and layout to respond
  3. Cancel any in-progress scroll behavior
  4. Correct the scroll position after everything settles

This is not generic JavaScript advice.
This is Webflow-specific reality.

The Reusable Solution Script

Here is the exact pattern we now use for TOCs, anchor links, and any in-page navigation that must work with sticky or animated headers.

The Scroll + Focus Utility Function

<script>
function scrollToElementWithOffset(target, offset = 100) {
  // Ensure the element can receive focus
  target.setAttribute("tabindex", "-1");
  target.focus();

  // Let Webflow/nav animations react first
  setTimeout(() => {
    const rect = target.getBoundingClientRect();
    const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
    const finalPosition = rect.top + scrollTop - offset;

    // Stop any competing scroll behavior
    window.stop();

    // Apply the corrected scroll position
    requestAnimationFrame(() => {
      window.scrollTo({
        top: Math.max(0, finalPosition),
        behavior: "smooth"
      });
    });
  }, 10);
}
</script>

How to Use It (Example: Table of Contents)

tocLink.addEventListener("click", event => {
  event.preventDefault();

  const targetId = tocLink.getAttribute("href").substring(1);
  const target = document.getElementById(targetId);
  if (!target) return;

  scrollToElementWithOffset(target, 100);
});

Why this works in Webflow

  • Focus happens before scrolling
  • The nav finishes animating
  • The final scroll position accounts for the header height
  • Focus remains visible
  • Keyboard, mouse, and screen reader users get the same experience

Accessibility Impact

This pattern directly supports:

  • WCAG 2.4.7 Focus Visible
  • WCAG 2.4.3 Focus Order
  • WCAG 2.1.1 Keyboard

And it prevents one of the most common “it technically works” failures in modern Webflow sites.

When You Should Use This Pattern

Use this approach whenever your Webflow site includes:

  • Sticky or animated navigation
  • Table of Contents components
  • Anchor links
  • “Jump to section” buttons
  • Footnotes or return-to-reference links
  • Any scripted in-page navigation

If focus needs to move and remain visible, this is the pattern to reach for.

Final Thoughts

This issue is easy to miss, even for experienced developers. Webflow’s interaction system adds behavior that most generic JavaScript tutorials don’t account for.

Now that we’ve hit this once and documented it, it’s officially part of our Graceful Web Studio accessibility toolkit.

If you’ve ever thought:

“Why does this work everywhere except Webflow?”

This is probably why.

Want to hire me to fix this issue for you. Send me a message on LinkedIn or call me 509-823-6780.

Your Website Deserves Better, Let's Team Up

We would love to meet with you face-to-face. Whether virtually or for a coffee. Book a call, and let’s find the right solution for you!

We review your site, map goals, and then deliver a clear plan and quote.