Skip to content

Engineering

Fixing Lighthouse Accessibility without guessing

Fix Accessibility audit findings from the rendered page evidence outward—route, failing node, automated rule—without guessing from a homepage percentage.

· by Priya Nair

Fixing Lighthouse Accessibility without guessing

Guessing looks like tweaking random ARIA until a percentage moves. Fixing looks like opening the route on the finding, locating the node the automated check flagged, and changing the markup or component API so the rendered page no longer fails that rule.

SlaySlop defines Accessibility audit as a check that "Runs automated accessibility checks in a rendered browser page." Your fix loop should honor that observer: real browser, finished DOM, specific page.

Outcome you want

Each audit finding either closes with a verified render pass on that route or stays open with a named owner. Sibling failures in Accessible names, Document semantics, and Viewport configuration get their own tickets instead of hiding under "make a11y green."

Boundaries

Permissioned, read-only scans. You fix code in your repo or CMS; the scanner does not edit the target. Automated checks are not a full WCAG conformance project. Do not "fix" by blocking the scanner or hiding the page from discovery while the public URL still fails for users.

Loading diagram.

Step 1: start from the page attachment

Product flow attaches findings to routes. Copy the URL from the finding. Load it in a real browser with the same viewport class you care about for handoff (often a mobile width plus desktop).

bash
# Permissioned reminder of the exact route under repair
printf '%s\n' "https://staging.example.com/checkout"
curl -sI "https://staging.example.com/checkout" | sed -n '1,12p'

Step 2: reproduce in the accessibility tree

In Chromium DevTools, inspect the control or region named by the finding. Confirm the computed name, role, and any contrast-related styles on the computed node. If the failure is structural, check landmarks and heading outline on that document.

text
fix_input:
  route: /checkout
  check: Accessibility audit (automated, rendered page)
  evidence: rule id + selector or description from report
fix_output:
  patched component
  re-scan or manual re-check on same route

Step 3: patch the source of truth, not the screenshot

Icon buttons need a required accessible name in the component API. Form fields need associated labels, not placeholder-only hints. Contrast failures usually need token changes in the design system, not a one-off hex on a single marketing page that will drift next sprint.

html
<!-- Before: anonymous icon control -->
<button type="button" class="icon-close">
  <svg aria-hidden="true"><!-- ... --></svg>
</button>

<!-- After: usable name on the control -->
<button type="button" class="icon-close" aria-label="Close dialog">
  <svg aria-hidden="true"><!-- ... --></svg>
</button>

If Document semantics is also failing on the same route, add landmarks and a sane heading outline in the layout shell. If Viewport configuration fails, fix the viewport meta and remove maximum-scale traps. Those are separate glossary checks; fixing them is still part of making the page usable, just not a substitute for the audit row.

Step 4: verify without score theater

Re-open the same route after deploy to staging. Confirm the node announces correctly and the automated finding clears on re-scan. Resist the urge to chase a different page's percentage while this route still fails.

Loading diagram.

Pitfalls while fixing

Silencing a rule in a config file does not fix the public surface. Adding aria-label="button" satisfies presence and fails "usable." Copying aria-hidden="true" onto meaningful text to clear a contrast noise complaint creates a worse assistive-tech outcome. Keep the Performance and accessibility product priority: slow, inaccessible, or unstable experiences first.

Step 5: cover the discovery gap

If Linked pages shows public routes you never opened during the fix sprint, schedule them. Automated checks cannot clear what they never rendered. Product language says quality audits run on discovered pages and findings attach to routes. Your verification list should match discovery, not the three URLs in the design Figma file.

text
verification_set:
  - routes from findings
  - routes from linked-pages discovery you ship publicly
  - one mobile + one desktop pass on primary conversion path

Writing the fix note clients understand

Editors and PMs need the route and the user-visible failure, not only the rule id. "Checkout close button had no accessible name after render" survives a call. "axe color-contrast on .btn-3" often does not. Keep both: machine id for engineers, plain outcome for handoff.

Related next step

When the backlog spans performance and accessibility on the same routes, keep both in one browser-context report. SlaySlop runs those audits after render and keeps evidence next to each issue.