Fixing Focus Visibility Issues with Sticky Navigation in Webflow


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:
Here’s the scenario:
This is especially common when:
From a keyboard or screen reader user’s perspective:
This is a real accessibility failure, not a cosmetic issue.
Before finding the fix, we tried all the “standard” approaches you’ll see recommended online.
scroll-margin-topThis 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.
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 key insight was this:
In Webflow, you must allow the navigation to react before you finalize scroll positioning.
The pattern that works is:
This is not generic JavaScript advice.
This is Webflow-specific reality.
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.
<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 WebflowThis pattern directly supports:
And it prevents one of the most common “it technically works” failures in modern Webflow sites.
Use this approach whenever your Webflow site includes:
If focus needs to move and remain visible, this is the pattern to reach for.
As I continued implementing this pattern across more complex Webflow projects, I ran into additional edge cases that required extending the original solution.
The original focus-first, scroll-last approach still worked conceptually, but certain layouts introduced new challenges that caused anchor targets to remain hidden behind sticky navigation systems.
This became especially noticeable when working with:
In these situations, standard anchor handling is often not enough. Even after calling preventDefault(), browser hash scrolling, focus behavior, and Webflow interactions can continue competing behind the scenes.
For more advanced implementations, I found it helpful to:
This last point turned out to be especially important in Webflow.
In some cases, sticky or animated navigation systems continue changing height or visibility after the initial scroll completes. A single correction pass may appear mathematically correct, while still leaving the target visually hidden once the interface finishes animating.
Running additional correction passes after short delays significantly improved reliability across browsers and screen sizes.
From a keyboard or screen reader user’s perspective, this issue can feel extremely disorienting.
Focus technically moves, but the focused content remains hidden behind navigation. Users lose visual context and may assume the page is broken.
For accessibility, visibility of focused content is just as important as focus movement itself.
This issue commonly appears in:
As Webflow projects become more interaction-heavy, accounting for these edge cases becomes increasingly important for creating a truly accessible experience.
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.
Work With Graceful Web Studio
We build accessible, conversion-focused Webflow websites for businesses across Yakima and the US. Crystal Scott is a Certified Professional in Web Accessibility (CPWA) with 11+ years of front-end experience.
Our services:
Transparent pricing on every service page. Request a quote and get a response within one business day.
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.
