The skip link on my own site took focus, held a full 180 by 52 pixel box at opacity 1, and painted nothing. It had been doing that for at least ten weeks, on the site whose accessibility page exists to prove I do not overclaim, and my own audit tool checked that link and passed it.
I was looking at something else
I was not auditing the skip link. I was building a new check.
WCAG 2.2 added SC 2.4.11 Focus Not Obscured (Minimum), which says that when something takes focus, the page cannot completely cover it. A sticky header is the ordinary way to fail it: you tab to a link near the top, the browser scrolls it into view, and the header parks itself on top of the thing you just focused. bekee.com got a sticky masthead on August 11, so I had a live page to build the check against, and I sat down to tab through it by hand and watch what happened.
The first stop on a tab through any WordPress block theme is the skip link. I pressed Tab, watched the top of the page, and nothing appeared. Focus was somewhere, because pressing Enter jumped me into the main content, so the link was there and it worked. It was not drawing.
What was wrong
My theme’s style.css hides visually-hidden text with the pattern most of us have been copying around since the 2000s, and that pattern sets the legacy clip property:
.screen-reader-text {
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
position: absolute;
/* ...and the rest of the boilerplate */
}
WordPress core un-hides the skip link on focus from its own stylesheet, at wp-includes/css/wp-block-template-skip-link.css. That rule resets clip-path. It does not reset clip, and there is a sensible reason for that: core’s own hiding never sets clip in the first place, so there is nothing for core to undo. Mine did. The legacy property survived focus and cropped the paint down to a one-pixel window, while every other signal on the element flipped to visible exactly as intended.
It was not a WordPress core regression, and it was not the sticky header. I forced the masthead to position: static and reproduced it on a page with nothing pinned to the top at all.
Who it failed, and who it did not
clip crops paint. It does not remove an element from the accessibility tree, which is the entire reason the pattern exists in the first place: the text is meant to stay available to a screen reader while it disappears from the screen. Focus landed on the link the whole time, and a screen reader announced it correctly the whole time. I put the bug back in a browser and listened to it with VoiceOver to be sure of that, because it decides who the failure belonged to.
The people it failed were sighted keyboard users. Somebody with a tremor, somebody who navigates by keyboard because a mouse hurts, somebody whose trackpad died on a Tuesday. That population is the entire reason a skip link is supposed to become visible on focus, and mine was serving them a control they could operate and could not see.
The criterion is SC 2.4.7 Focus Visible, Level AA, in the standard since 2008. I have seen this kind of failure called a Bypass Blocks failure too, and I do not think it is one. SC 2.4.1 asks for a mechanism that skips repeated blocks, and the mechanism existed, took focus, and worked when you pressed Enter. What failed is the part that tells a sighted person the mechanism is there.
There is an irony in the sequence that I am not going to pretend I planned. I was implementing a criterion published in 2023 and found a criterion from 2008 quietly failing underneath it.
How long it had been that way
The clip line has been in style.css since the theme repo’s first commit, 8fcd588 on 2026-06-02. That is at least ten weeks. The repo does not reach back to the site’s relaunch on April 26, so I cannot tell you whether it shipped broken on day one, and I am not going to round it into a number that sounds better.
Why every check passed it
This is the part worth your attention, and it is the reason I am writing the post at all.
On focus, the element had a computed width of 180 pixels, a height of 52, opacity: 1, visibility: visible, and a z-index of 100000. Its clip-path was reset. Every signal a program usually reads to answer “can the user see this” read normal, and each of those readings was correct. The element had every one of those properties. It also painted nothing.
My audit tool’s SkipLinkCheck had a property called visibleWhenFocused, and what it did was read the computed style. It reported a pass on the exact link that was failing, on my own site, every time it ran.
This is the third time
If the argument stopped there, it would be a weak one. Automation missed a bug, a human caught it, and I taught the tool to catch it next time. A reader who has been around tooling would take one look and conclude that my scanner had a defect and now does not, which is a smaller story than the one I think is here.
The real shape is that I have now made this same mistake three times, in three different checks.
In July I moved the focus-indicator check off the stylesheet and onto a pixel diff of the element before and after focus, because focus can legitimately be shown with a border, with a background shift, or with a pseudo-element, and reading the CSS for an outline finds one of those and misses the other three. Before that, I moved the text-over-image contrast measurement onto rendered pixels, which is the whole subject of measuring the right pixels. Now the skip link, which was the last style-only visibility claim left in the keyboard lane.
Three separate checks, written months apart, each one reaching for declared style when the question was about rendered output. I keep reaching for it because it is right there, it is cheap to read, and it reads like the truth. The tool did not have one blind spot that got fixed; it kept regenerating the same blind spot in each new check I wrote, and a person is what noticed all three times.
That is why I keep a human in the loop, and it is an argument that survives “well, now the tool catches it.” The next check I write will want to read style too.
What the tool does now
visibleWhenFocused hit-tests. It calls document.elementsFromPoint, which returns the whole stack of elements at a coordinate rather than only the topmost one, and reads the answer three ways:
- the element is on top of the stack, so it paints and nothing covers it, which passes
- the element is in the stack but not on top, so something is covering it, which is SC 2.4.11
- the element is absent from the stack, so it paints nothing at all, which is SC 2.4.7
That distinction matters more than it looks, because the two failures send a developer to two different files.
One detail from building it, because it is the kind of mistake that makes a report actively harmful. The presence test has to accept only the element itself and its descendants, never an ancestor. Every stack at every coordinate contains body and html, and both of those contain the element you are asking about, so an ancestor-accepting test returns true everywhere and always. My first run reported the skip link as covered rather than absent, which is a report that would have sent someone to go look at the sticky header while the actual bug sat in the theme stylesheet.
The fix on the site
clip is the property that has to be reversed, and here is the rule that shipped:
.skip-link.screen-reader-text:focus,
.skip-link.screen-reader-text:focus-visible,
a.skip-link:focus,
a.skip-link:focus-visible {
clip: auto !important;
clip-path: none !important;
position: fixed !important;
/* plus the visual styling */
}
The !important is load-bearing, so leave it in if you paste this. Core’s own skip-link focus rule is competing for the same element, and a plain clip: auto can lose to it, which looks exactly like the fix doing nothing.
I did not stop at the unclip, because a skip link drawn in default browser styling on a dark site reads as a rendering error rather than as a control. It takes the site’s own colors now, with an orange focus ring around it, and it measures 13.88:1 for the text and 8.72:1 for the ring against the page behind it. A keyboard walk across twelve pages afterward returned zero skip-link findings and zero focus-visibility findings. That walk pressed Tab and never Shift+Tab, so it is a forward-only result.


What I would take from it
Build the check, and drive the page by hand while you build it. I found this one because I needed a fixture for SC 2.4.11 and my own site was the closest page to hand, so I spent twenty minutes tabbing through it looking at the screen instead of at a report.
Automation finds what you told it to look for.
The unstructured look at everything else is the part that finds what you did not know to ask about, and building a new check is one of the few times you are guaranteed to be doing that anyway.
The other half of it is a rule I should have written down after the second instance: any claim that a person can see something has to be tested against what the browser painted, never against what the stylesheet declared. Every one of my style-only visibility checks has eventually turned out to be wrong, and this was the last one.
If you are evaluating somebody’s audit, that is the question I would ask them. Not which rules the tool covers, because the coverage list is the easy part and axe-core is free. Ask what their tool got wrong, and how they found out.