Repository navigation
Fix accessibility violations on the live site - #26
Merged
Merged
Conversation
axe-core 4.14 (WCAG 2.0/2.1/2.2 A+AA plus best-practice) over every route in the sitemap, both languages, desktop and mobile: 222 violations across 7 types. This branch takes it to zero. Deliberately cut from main rather than from the landing-page work, so it can ship on its own: these defects are live today and the fixes do not depend on any redesign decision. Contrast (WCAG 1.4.3) --color-primary as a text colour is 3.10:1 on dark and 2.68:1 on grey, below AA everywhere it was used. Text uses now take --color-primary-text (5.29 / 4.58); background and border uses are unchanged. --color-light is 4.09:1 on grey, so small text moves to --color-muted. Chroma's monokai comment colour is 3.03:1 on its own background; github-dark clears it at 6.15:1. Links in prose (WCAG 1.4.1) Body-copy links were distinguished by colour alone, at 1.36:1 against the surrounding text. Now underlined. Headings List pages had no h1: their section title is now the page heading, and cards within move from h3 to h2 so levels never skip. Team profiles made the generic "About Member" label the only heading and the person's name an h3; the name is now the h1 and the label is no longer a heading. A news post started at h3. A section with no title rendered an empty h2. Landmarks and bypass (WCAG 1.3.1, 2.4.1) The banner sat outside <main>. There was no skip link at all. Reflow (WCAG 1.4.10) Long code lines widened the whole page at 320px instead of scrolling inside their own block. Empty page /funfacts/ published a page with no content and no heading; it is data for the home-page counters, so it no longer renders as a page. The counters and the background image are unaffected. Robustness .reveal starts at opacity 0 and is shown by scroll-reveal.js, so content was gated on JavaScript and on the observer firing. It is now visible immediately under prefers-reduced-motion, with a <noscript> fallback. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
✅ Preview deployed at https://26--capro-uio.netlify.app |
Adds scripts/a11y and wires it into the preview workflow, so the audit
runs against the deployed preview and fails the job on a regression.
The report is posted as a PR comment.
Two passes: axe-core (WCAG 2.0/2.1/2.2 A+AA plus best-practice) at
desktop and mobile including the nav states that only exist after a
click, then the checks axe cannot make — skip link, keyboard order,
focus indicators, reduced motion, reflow at 320 and 640px, and per-page
lang/title/alt/link labels.
By default it scans one page per layout (each language's home page,
each section landing page, the first child of each section): 30 routes
rather than 122, about 90 seconds. `--all` sweeps the whole sitemap.
Three things the script has to get right, all documented in its README
because each produced a false result while this was being written:
settle animations before sampling colour, or a mid-fade composite
reports contrast failures that do not ship; resize the viewport rather
than setting body{zoom} to emulate zoom, because only the former moves
the CSS viewport and triggers media queries; and skip meta-refresh
stubs before navigating, or axe audits the destination site.
Verified both directions: clean against this branch, and exit 1 with a
correct report against a branch that still has the violations.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
✅ Accessibility: no issuesaxe-core over 31 routes × 2 viewports (one page per layout), plus 67 manual checks. All 67 manual checks passed. Automated tooling catches roughly a third of accessibility problems. A clean run is a floor, not a ceiling. |
Both were invisible to the local runs that declared this branch clean, which is the point of running the audit against the deployed preview. Leaflet attribution links were #0078a8 on #333 text (2.55:1), under the 3:1 that link-in-text-block requires. Darkening moves them closer to the surrounding text, so they are underlined instead; the colour itself is 4.94:1 on the control's white background. The override has to live outside @layer components. Leaflet's stylesheet is unlayered and loads after ours, and unlayered styles beat layered ones regardless of specificity or order, so the first attempt compiled fine and did nothing. Verified the computed style this time, not just the generated CSS. The 404 page's heading used text-primary: 2.68:1 on grey, under the 3:1 large text needs. It surfaced only because a removed route now serves the 404, so the scanner was auditing it unawares. The 404 is a page real users land on, so it is now scanned deliberately, and routes that do not return 200 are skipped rather than silently audited under the wrong URL. Also waits for Leaflet to render before scanning: it paints after networkidle2, so the attribution was sometimes absent and results flipped between runs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why this is separate
Cut from
main, not from the landing-page work, so it can merge on its own. These defects are live today and none of the fixes depend on any redesign decision. PRs #23, #24 and #25 can rebase onto this and inherit them.What was found
axe-core 4.14 (WCAG 2.0/2.1/2.2 A + AA, plus best-practice) over every route in the sitemap, both languages, desktop and mobile, including the open mobile menu — 222 violations across 7 types. Now zero, plus 44/44 manual checks.
--color-primaryas a text colour is 3.10:1 on dark, 2.68:1 on grey — below AA everywhere it appeared. Text uses now--color-primary-text(5.29/4.58); background and border uses unchanged.--color-lightis 4.09:1 on grey, so small text moved to--color-muted. Chroma's monokai code comments were 3.03:1 → github-dark at 6.15:1.h1at all. Their section title is now the page heading, with cards moving h3 → h2 so levels never skip. Team profiles made the generic "About Member" the only heading and the person's name anh3— the name is now theh1. A news post started ath3. A titleless section rendered an emptyh2.<main>. There was no skip link at all./funfacts/published a page with no content and no heading. It is data for the home-page counters, so it no longer renders as a page — counters and background image unaffected.The one worth reading about
.revealstarts atopacity: 0and is only revealed byscroll-reveal.js. All page content was gated on JavaScript running and on the IntersectionObserver firing. It now renders immediately underprefers-reduced-motion, with a<noscript>fallback. This bit me twice while testing — screenshots caught blank sections mid-fade, which is the same failure a crawler, a print stylesheet or a headless renderer would hit.Test plan
CI builds both languages. What it does not check, and what I ran manually:
prefers-reduced-motionhonoured and content still visible without the observerlangandtitleon every pageTwo honest caveats:
body { zoom }does not shrink the CSS viewport, so media queries never switch to mobile). Corrected to resize the viewport, which is what browser zoom actually does. The nav is fine; the code blocks genuinely were not.🤖 Generated with Claude Code