Accessibility Case Study

WCAG 2.1 Audit &
Remediation Report

A structured accessibility audit of labunknown.ca — identifying WCAG 2.1 AA failures through automated and manual methods, applying code fixes, and measuring the impact through before/after Lighthouse testing.

Site labunknown.ca Designer Miyoung Cho Date March 21, 2026 Standard WCAG 2.1 Level AA Tools Lighthouse · Manual HTML Review

Executive Summary

This report documents a full accessibility audit cycle for Lab Unknown, a static portfolio site built with HTML/CSS/JS and deployed on Netlify. The audit followed a structured methodology combining automated Lighthouse testing with manual WCAG 2.1 code review, revealing a significant gap between what automated tools detect and what truly affects users.

The audit identified 16 distinct accessibility issues across 3 priority levels. Of these, only 1 category (color contrast) was detected by Lighthouse. The remaining 11 structural and semantic issues — including missing landmarks, keyboard focus styles, and dynamic ARIA state — were found exclusively through manual review.

Lighthouse Accessibility Score
87
100
+13 points
labunknown.ca · Homepage · Chrome Lighthouse 13
Issues Found & Fixed
16
Total found
16
Fixed
2
Files modified
Across style.css and index.html

Methodology

The audit used a two-track approach: automated scanning via Google Lighthouse, and manual code inspection against WCAG 2.1 Level AA success criteria. Results from both tracks were then cross-referenced to produce a gap analysis.

01

Lighthouse Automated Scan

Chrome DevTools → Lighthouse → Accessibility audit on the live site (labunknown.ca). Captured all failing audits, passing audits, and not-applicable checks. Baseline score: 87/100.

02

Manual WCAG 2.1 Code Review

Full review of HTML source against WCAG 2.1 AA success criteria: semantic structure, keyboard navigation, ARIA patterns, color contrast ratios, motion, and dynamic state management.

03

Gap Analysis

Cross-referenced both result sets to identify what each method caught, missed, or overlapped — producing a prioritized fix list and insight into tool limitations.

04

Code Remediation

Applied fixes to style.css and index.html, following the existing design system and code conventions.

05

Verification & Deployment

Deployed updated files to Netlify (drag-and-drop). Re-ran Lighthouse on the live site. Final score: 100/100 Accessibility.

Lighthouse Findings (Automated)

Lighthouse version 13 identified one failing audit category on the homepage, affecting 11 distinct elements. All other checks either passed or were not applicable.

Failed Audits

Audit WCAG Failing Elements Status
Color Contrast
Background and foreground colors do not have a sufficient contrast ratio
1.4.3 AA .featured-label (×2)
.featured-more (×2)
.home-about-btn-solid
.home-insights-more
.footer-copy
.footer-built (×3 links)
Failed

Passed Audits

AuditWCAG
Document has a <title> element2.4.2
<html> element has a valid [lang] attribute3.1.1
Image elements have [alt] attributes1.1.1
Links have a discernible name2.4.4
[user-scalable="no"] not used in viewport meta1.4.4
[aria-hidden="true"] not present on <body>4.1.2

Manual Review Findings

Manual inspection of the HTML/CSS source code against WCAG 2.1 AA criteria identified 16 issues across 4 categories. These are organized by priority.

P1 — Color Contrast (WCAG 1.4.3)

All gray-4 (#999999) text on white background fails the 4.5:1 minimum contrast ratio for normal text.

ElementBeforeContrast RatioAfterContrast Ratio
.featured-label #999 on white 2.85:1 #555 on white 7.46:1
.featured-more #999 on white 2.85:1 #555 on white 7.46:1
.home-about-btn-solid white on #FF5C00 3.09:1 #0a0a0a on #FF5C00 6.40:1
.home-insights-more #999 on white 2.85:1 #555 on white 7.46:1
.footer-copy #999 on white 2.85:1 #555 on white 7.46:1
.footer-built & links #999 on white 2.85:1 #555 on white 7.46:1

Note on the orange button: The brand accent color #FF5C00 was preserved. Only the button text color was changed from white to near-black, maintaining full brand identity while achieving a 6.40:1 contrast ratio — well above the 4.5:1 requirement.

Before Meet Miyoung → White on #FF5C00 — 3.09:1 ❌
After Meet Miyoung → Black on #FF5C00 — 6.40:1 ✅

P2 — Structure & Semantic HTML (WCAG 1.3.1, 2.4.1)

IssueWCAGImpactFix Applied
No skip navigation link 2.4.1 A Keyboard users must tab through all nav links to reach content on every page load Added <a href="#main-content" class="skip-link">
No <main> landmark 1.3.1 A Screen reader users cannot jump directly to main content via landmark navigation Wrapped page content in <main id="main-content">
<section> elements without accessible names 1.3.6 AAA Sections are announced as "region" without context in screen readers Added aria-label to all 5 sections
Marquee not hidden from AT 1.1.1 A Screen readers announce repeated skill tags — adds noise, no informational value Added aria-hidden="true" role="presentation"
Decorative canvas not hidden from AT 1.1.1 A Bubble animation canvas may be announced as an interactive element Added aria-hidden="true" to canvas

P2 — Dynamic ARIA State (WCAG 4.1.2)

IssueWCAGImpactFix Applied
Hamburger menu: aria-expanded not updated by JS 4.1.2 A Screen reader users cannot know if the mobile menu is open or closed JS now toggles aria-expanded true/false on click
Hamburger menu: no aria-controls 4.1.2 A No programmatic link between button and the menu it controls Added aria-controls="nav-menu", assigned matching id
Navigation green dot not hidden from AT 1.1.1 A Screen reader announces decorative status dot unnecessarily Added aria-hidden="true" to dot span

P3 — Keyboard & Motion (WCAG 2.4.7, 2.3.3)

IssueWCAGImpactFix Applied
No :focus-visible styles 2.4.7 AA Keyboard users cannot see which element is focused while navigating Added 2px orange outline for all focusable elements via :focus-visible
No prefers-reduced-motion support 2.3.3 AAA Marquee, fade-ins, and bounce animations run regardless of system motion preference — may cause discomfort for users with vestibular disorders Added @media (prefers-reduced-motion: reduce) — disables all animations

Code Changes Applied

1. Skip Link + Focus Styles — style.css

Before — Not present
/* No skip link styles */ /* No :focus-visible styles */
After — Added
.skip-link { position: absolute; top: -100%; left: 16px; background: var(--accent); color: var(--white); padding: 10px 20px; z-index: 99999; } .skip-link:focus { top: 0; } :focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

2. Footer Color Contrast — style.css

Before
.footer-copy { color: var(--gray-4); } .footer-built { color: var(--gray-4); } .footer-built a { color: var(--gray-4); }
After
.footer-copy { color: var(--gray-5); } .footer-built { color: var(--gray-5); } .footer-built a { color: var(--gray-5); }

3. Reduced Motion — style.css

Before — Not present
/* No motion preference support */
After — Added
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } .marquee-track { animation: none; } .fade-in { opacity: 1; transform: none; transition: none; } * { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; } }

4. Skip Link + Main Landmark — index.html

Before
<body> <nav class="nav"> ... </nav> <div class="page"> <section class="hero"> ...
After
<body> <a href="#main-content" class="skip-link"> Skip to main content </a> <nav class="nav">...</nav> <main id="main-content"> <div class="page"> <section class="hero"> ...

5. Hamburger aria-expanded — index.html JS

Before
hamburger.addEventListener( 'click', () => { nav.classList .toggle('open'); // aria-expanded never updates } );
After
hamburger.setAttribute( 'aria-expanded', 'false'); hamburger.addEventListener( 'click', () => { const isOpen = nav.classList.toggle('open'); hamburger.setAttribute( 'aria-expanded', isOpen ? 'true' : 'false'); } );

Gap Analysis: Lighthouse vs. Manual Review

This section documents what each method found, missed, and why — the core insight of this case study.

Lighthouse Caught
Color contrast on 11 specific elements — precise, element-level detail
Confirmed lang attribute, title, alt texts are present
Confirmed viewport meta is not blocking zoom
Manual Review Caught
Missing skip link — keyboard users affected every page load
Missing <main> landmark — screen reader navigation broken
aria-expanded not updating — screen readers get wrong state
No :focus-visible — keyboard users can't see where they are
No prefers-reduced-motion — vestibular disorder risk
Decorative marquee, canvas announced by screen readers
Sections without accessible names — navigation context lost
Lighthouse Missed
Skip link — marked "not applicable" even when no skip link exists
<main> landmark — not in Lighthouse audit scope
aria-expanded JS state — only checks static HTML, not runtime behavior
:focus-visible — not in Lighthouse audit scope
prefers-reduced-motion — not in Lighthouse audit scope
Section aria-labels — not in Lighthouse audit scope
Manual Missed
⚠️Footer link colors — identified the variable issue but not each specific element
⚠️Exact element-level contrast mapping — Lighthouse was more precise here
"Lighthouse tells you what values are wrong. Manual review tells you what's missing entirely. A perfect Lighthouse score is achievable with color fixes alone — but real accessibility requires both automated testing and human judgment."

Tool Capability Comparison

Lighthouse
Color contrast (element-precise)
HTML attribute presence
Fast, repeatable, scoreable
Dynamic/JS state
Landmark structure
Keyboard UX patterns
Motion/animation
Manual Review
Semantic structure
JS runtime behavior
Keyboard navigation flow
Motion & animation
UX context & intent
⚠️Slower, requires expertise
⚠️Can miss element-level detail
Combined (This Audit)
Element-precise contrast
Structural completeness
Runtime ARIA state
Keyboard UX
Motion accessibility
Verifiable score change
Documented before/after

Results

Lighthouse MetricBeforeAfterChange
Accessibility 87 100 +13
Performance 91 93 +2
Best Practices 77 77
SEO 91 91
Fix CategoryIssues FixedFilesWCAG Criteria
Color Contrast 6 element groups (11 elements) style.css, index.html 1.4.3 AA
Skip Link 1 style.css, index.html 2.4.1 A
Main Landmark 1 index.html 1.3.1 A
Section Labels 5 sections index.html 1.3.6 AAA
Dynamic ARIA State 3 (expanded, controls, dot) index.html 4.1.2 A
Decorative Elements 2 (marquee, canvas) index.html 1.1.1 A
Focus Visibility 1 style.css 2.4.7 AA
Reduced Motion 1 style.css 2.3.3 AAA

Final Result

87
Before
100
After

Lighthouse Accessibility · labunknown.ca · Chrome DevTools · March 2026

Key Takeaways

1. Automated tools score, but don't see everything

Lighthouse caught the only issue it's designed to catch well — color contrast — but missed 11 of the 16 issues found in this audit. A score of 87 felt "almost there," but the actual experience for keyboard and screen reader users had significant gaps.

2. The most impactful issues are often invisible to automated scanners

Missing landmarks, improper ARIA state management, and lack of focus styles all affect real users daily but produce no Lighthouse penalty. Manual review is the only way to find them.

3. Design system decisions cascade into accessibility

The root cause of all 6 contrast failures was a single CSS variable: --gray-4: #999999 being used for informational text. One token decision affected 11 elements across the page. Accessibility-first design system documentation would have prevented this.

4. Brand color can be preserved while fixing contrast

The orange accent #FF5C00 is a core brand element. Rather than changing the color, we changed the text on top of it from white to near-black — achieving a 6.40:1 ratio while keeping the exact same brand feel.

5. prefers-reduced-motion is a safety issue, not just a preference

For users with vestibular disorders, persistent marquee animations and scroll-triggered fade effects can cause physical discomfort. The prefers-reduced-motion media query is a simple, high-impact fix that takes minutes to implement.

Lab Unknown · Accessibility Case Study · March 2026
WCAG 2.1 Level AA · Google Lighthouse 13 · labunknown.ca