<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: perceivable</title>
    <description>The latest articles on DEV Community by perceivable (@perceivable).</description>
    <link>https://dev.to/perceivable</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4161498%2F89c4ad90-ed41-42cc-a1f9-41528ea82e13.png</url>
      <title>DEV Community: perceivable</title>
      <link>https://dev.to/perceivable</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/perceivable"/>
    <language>en</language>
    <item>
      <title>I ran my accessibility checker against gov.uk. It found 72 violations — all of them were mine.</title>
      <dc:creator>perceivable</dc:creator>
      <pubDate>Sun, 04 Oct 2026 11:46:55 +0000</pubDate>
      <link>https://dev.to/perceivable/i-ran-my-accessibility-checker-against-govuk-it-found-72-violations-all-of-them-were-mine-5fp0</link>
      <guid>https://dev.to/perceivable/i-ran-my-accessibility-checker-against-govuk-it-found-72-violations-all-of-them-were-mine-5fp0</guid>
      <description>&lt;p&gt;I built a Chrome extension that checks pages against the automatable parts of WCAG 2.2 AA. This post isn't really about the extension. It's about what happened when I stopped trusting it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The control group
&lt;/h2&gt;

&lt;p&gt;Once the checker worked, the first thing I did was point it at &lt;strong&gt;gov.uk&lt;/strong&gt;. The UK government's site has a long, public record of taking accessibility seriously. If my tool reported problems there, the sensible assumption was that the tool was wrong, not the site.&lt;/p&gt;

&lt;p&gt;It reported &lt;strong&gt;72 violations&lt;/strong&gt;. Every one of them was a bug in my code.&lt;/p&gt;

&lt;p&gt;So I made that the method. I picked sites built by people who do accessibility for a living — gov.uk, WebAIM, Deque, The A11Y Project, the W3C's WAI pages — and treated anything reported on them as my bug until proven otherwise.&lt;/p&gt;

&lt;p&gt;Six real defects came out of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. I skipped the WCAG 2.5.8 Spacing exception
&lt;/h2&gt;

&lt;p&gt;2.5.8 Target Size (Minimum) is new in WCAG 2.2: pointer targets should be at least 24×24 CSS pixels. The naive implementation is one line — read &lt;code&gt;getBoundingClientRect()&lt;/code&gt;, compare against 24.&lt;/p&gt;

&lt;p&gt;But the criterion has five exceptions, and one of them does most of the work:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spacing: an undersized target passes if a 24px-diameter circle centred on it doesn't intersect another target, or another undersized target's circle.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The real question 2.5.8 asks isn't "is it big enough?" — it's "is there room to miss without hitting something else?" A 20px icon button with generous margin is fine. Three 16px buttons packed 2px apart are not.&lt;/p&gt;

&lt;p&gt;Without the spacing check: 72 violations on gov.uk. With it: &lt;strong&gt;zero&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. I measured contrast on text nobody can see
&lt;/h2&gt;

&lt;p&gt;This is the standard way to give an icon button a screen reader label:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.icon-button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text-indent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-5000px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The text is in the DOM but never painted. I was faithfully measuring its colour contrast — which is meaningless.&lt;/p&gt;

&lt;p&gt;The fix: measure the &lt;strong&gt;text node&lt;/strong&gt; with a &lt;code&gt;Range&lt;/code&gt;, not the element's box, and check that its rect survives every ancestor with &lt;code&gt;overflow&lt;/code&gt; clipping. If it's clipped away, there's nothing to measure.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. My accessible-name computation ignored &lt;code&gt;aria-label&lt;/code&gt; on descendants
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/nvidia"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"img"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Nvidia"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That link is correctly named. My code collected text nodes only, found none, and reported it as a link with no discernible text.&lt;/p&gt;

&lt;p&gt;In the accname spec, "name from content" recursively takes each descendant's &lt;em&gt;accessible name&lt;/em&gt;, not its raw text. That one bug produced &lt;strong&gt;30 false findings on stripe.com&lt;/strong&gt; alone. Logo links and icon links are everywhere — shipped as-is, it would have cried wolf on most of the web.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. I called a zero-height element "too small"
&lt;/h2&gt;

&lt;p&gt;On a11yproject.com:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Target is 320×0px, below the 24×24 minimum
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A link inside a collapsed panel. Something with no height doesn't have a small hit area — it has none. The message was describing a box, not a target.&lt;/p&gt;

&lt;p&gt;Now the hit area is the union of the element's box and its rendered descendants (clicks on a child are routed to the enclosing link), and if that union is still degenerate, the element is skipped.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. I told Deque — who make axe — that their site had six violations
&lt;/h2&gt;

&lt;p&gt;The rule: "focusable element inside &lt;code&gt;aria-hidden&lt;/code&gt;". A keyboard user can reach it, a screen reader user can't perceive it — a real and common bug.&lt;/p&gt;

&lt;p&gt;Except every one of the six was inside a &lt;code&gt;display: none&lt;/code&gt; subtree. A closed dropdown. Those elements aren't in the tab order at all; the browser skips them just as the screen reader does. No mismatch.&lt;/p&gt;

&lt;p&gt;The distinction matters because the &lt;em&gt;real&lt;/em&gt; version of this bug is extremely common: an off-canvas menu shoved off-screen with a transform, still &lt;code&gt;display: block&lt;/code&gt;, still tabbable, marked &lt;code&gt;aria-hidden&lt;/code&gt;. Tab into it and focus vanishes. That one the tool should — and now does — still catch.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. I read 2.4.4 as if it were AAA
&lt;/h2&gt;

&lt;p&gt;I was failing links like "Read more" and "Learn more".&lt;/p&gt;

&lt;p&gt;But 2.4.4 is &lt;strong&gt;Link Purpose (In Context)&lt;/strong&gt;. A "Read more" whose purpose is clear from the card it sits in conforms. Requiring the link text to stand on its own is &lt;strong&gt;2.4.9&lt;/strong&gt;, which is Level AAA.&lt;/p&gt;

&lt;p&gt;This wasn't a code bug; it was a misreading of the spec. I suspect it's a common one. It's now reported as "needs review", not as a failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it stands
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Site&lt;/th&gt;
&lt;th&gt;Violations reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;gov.uk&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;webaim.org&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;deque.com&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;a11yproject.com&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;w3.org/WAI&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Sites with genuine problems still light up — which is the other half of the test.&lt;/p&gt;

&lt;p&gt;Every fix has a regression test. The one that actually keeps the tool honest is a single file, &lt;code&gt;test/clean.html&lt;/code&gt;: a correctly built page that &lt;strong&gt;must produce zero violations&lt;/strong&gt;. Anything flagged there is a false positive by definition.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I took from it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;When an automated accessibility report contradicts a site with real expertise behind it, check the tool first.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And be honest about what automation can do at all. Automated checks find roughly a third of accessibility barriers. Whether alt text is accurate, whether a keyboard user can finish a checkout, whether a page makes sense read aloud — no tool answers those. So this one reports what it can't decide as "needs review" instead of guessing, and says so in its UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you want to try it
&lt;/h2&gt;

&lt;p&gt;It's free, has no account, and makes &lt;strong&gt;no network calls at all&lt;/strong&gt; — the privacy policy depends on that, so there's a test that fails the build if anyone adds one. The source is public.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chrome Web Store: &lt;a href="https://chromewebstore.google.com/detail/ldbmeaihgdlghenedbhafkfikefnmicb" rel="noopener noreferrer"&gt;https://chromewebstore.google.com/detail/ldbmeaihgdlghenedbhafkfikefnmicb&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Source: &lt;a href="https://github.com/perceivable/a11yscope" rel="noopener noreferrer"&gt;https://github.com/perceivable/a11yscope&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The 2.5.8 exceptions, in detail: &lt;a href="https://perceivable.github.io/guides/wcag-target-size/" rel="noopener noreferrer"&gt;https://perceivable.github.io/guides/wcag-target-size/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;If you find it flagging correct markup, please tell me.&lt;/strong&gt; A scanner that cries wolf is worse than no scanner, and every report so far has become a regression test.&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
