Accessibility validation (WCAG 2.2 Level AA)
Description
Systematic validation of WCAG 2.2 Level AA accessibility compliance BEFORE committing ANY HTML. This Skill prevents the accessibility issues that required 5+ Lighthouse audit cycles in the Colors project by catching problems early in development.
When to use this Skill
ALWAYS use this Skill:
- •Before committing ANY HTML file
- •After creating new stations or demos
- •After editing existing HTML content
- •Before running Lighthouse audits
- •When adding new color combinations
- •When adding interactive elements
NEVER commit HTML without running through this checklist.
Progressive validation steps
Step 1: Text contrast validation
Check ALL text meets minimum contrast ratios against backgrounds.
WCAG AA requirements:
- •Normal text (< 18px): 4.5:1 contrast minimum
- •Large text (≥18px or ≥14px bold): 3:1 contrast minimum
HAP Learning Lab color system (pre-validated for cream/peach backgrounds):
Single source of truth: All color values are defined in
css/style.cssusinghsl()format with alpha channel where needed. See:rootvariables (lines 40-100) for actual color values.
Text on cream/peach backgrounds (--cream-white, --peach-background):
- • Normal body text uses
--dark-brown— 9.5:1 contrast ✅ - • Secondary text uses
--medium-brown— 5.3:1 contrast ✅ - • Links/interactive uses
--teal-darker— 4.5:1 contrast ✅ - • Large bold orange uses
--orange-darker— 3.1:1 contrast ✅ - • Normal orange text uses
--orange-darkest— 4.5:1 contrast ✅
Status indicators:
- • Success text uses
--success-darker— 4.5:1 contrast ✅ - • Error text uses
--error-darker— 4.5:1 contrast ✅
Validation tools:
- •Chrome DevTools → Elements → Accessibility pane (shows contrast ratio)
- •WebAIM Contrast Checker: https://webaim.org/resources/contrastchecker/
- •Lighthouse audit (catches contrast issues)
Common mistakes:
- •❌ Using base
--warm-orangefor normal text (only 2.7:1 contrast — fails WCAG AA) - •❌ Using light colors on light backgrounds
- •❌ Hardcoding hex or rgb() colors instead of using CSS custom properties
- •❌ Custom colors without validation
Step 2: Semantic HTML validation
Check page uses proper semantic elements (NOT generic divs).
Required semantic structure:
- •
<header>for page header (NOT<div class="header">) - •
<nav>for navigation sections (witharia-label) - •
<main id="main-content">for main content (ONE per page) - •
<article>for station content - •
<section>for content sections - •
<footer>for page footer - •
<aside>for supplementary content (if applicable)
Heading hierarchy validation:
- • ONE
<h1>per page (page title) - •
<h2>for section headings - •
<h3>for subsection headings - • NO skipped levels (h1 → h3 without h2)
- • NO empty headings (
<h3></h3>)
Validation command (run in DevTools console):
// Check for empty headings
Array.from(document.querySelectorAll('h1, h2, h3, h4, h5, h6'))
.filter(h => h.textContent.trim() === '').length
// Should return: 0
Step 3: ARIA labels validation
Check all landmarks and navigation have descriptive labels.
Required ARIA labels:
- •
<nav aria-label="Page navigation">— Top station navigation - •
<nav aria-label="Bottom navigation">— Bottom station navigation - •
<nav aria-label="Learning stations">— Hub page stations grid - •
<main id="main-content">— Main content landmark
Interactive elements:
- • Buttons have descriptive
aria-labelwhen icon-only - • Links have descriptive text (NOT "click here")
- • Form inputs have associated
<label>elements
Validation check:
- • All
<nav>elements havearia-label - • All interactive elements have accessible names
- • No generic labels ("Navigation 1", "Section 2")
Step 4: Keyboard navigation validation
Check all interactive elements are keyboard accessible.
Tab order validation:
- • Skip link is FIRST element in
<body> - • Tab order follows visual order
- • ALL interactive elements receive focus
- • Focus indicator visible on ALL elements
Skip link requirement (MUST be first in body):
<body>
<a href="#main-content" class="skip-link">Skip to main content</a>
<!-- Rest of page -->
</body>
Main content ID:
<main id="main-content">
Test procedure:
- •Load page in browser
- •Press Tab key repeatedly
- •Verify skip link appears first
- •Verify all interactive elements get focus
- •Verify focus indicator clearly visible
Step 5: Color independence validation
Check information is NOT conveyed by color alone.
Requirements:
- • Success/error states have icons AND color (NOT just green/red)
- • Links distinguishable from text (underline, bold, or icon)
- • Interactive elements have text labels (NOT just colored backgrounds)
- • Charts/graphs have labels AND colors
Good patterns:
- •✅ "✅ RIGHT: What I Learned" (checkmark + color + text)
- •✅ "❌ WRONG: HAP's Old Way" (X + color + text)
- •✅ Links with underline + color
Bad patterns:
- •❌ Red text only for errors (no icon)
- •❌ Green background only for success (no text/icon)
- •❌ Color-only status indicators
Step 6: Image accessibility validation
Check ALL images have proper alt text and attributes.
Required image attributes:
<img src="[url]"
alt="[Descriptive text]"
width="[width]"
height="[height]"
decoding="async"
[loading="lazy"]
[fetchpriority="high"]>
Alt text rules:
- • ALL images have
altattribute (required) - • Descriptive alt text (NOT "image of...")
- • Decorative images:
alt=""(empty, not omitted) - • Complex images: alt + longdesc or caption
- • HAP character: "HAP at his laptop" / "HAP looking excited" (describes expression)
Image loading optimization:
- •
widthandheightattributes present (prevents layout shift) - •
decoding="async"on most images - •
loading="lazy"on below-fold images - •
fetchpriority="high"ONLY on LCP image (HAP avatar)
Validation:
// Check for images without alt
Array.from(document.querySelectorAll('img')).filter(img => !img.hasAttribute('alt')).length
// Should return: 0
Step 7: Pre-commit checklist
Run this checklist before EVERY commit:
Accessibility fundamentals:
- • Skip link is first element in body
- • Main content has
id="main-content" - • All nav elements have
aria-label - • One
<h1>per page, proper heading hierarchy - • All images have alt text
- • All images have width/height attributes
Color and contrast:
- • All text meets 4.5:1 contrast (or 3:1 for large text)
- • Using approved HAP color variables for text
- • No color-only information (always paired with text/icons)
Semantic HTML:
- • Using semantic elements (
<header>,<nav>,<main>,<footer>) - • No empty headings
- • No skipped heading levels
Keyboard navigation:
- • Tab through entire page works
- • Focus indicators visible
- • All interactive elements reachable by keyboard
Step 8: Lighthouse validation
After passing manual checks, validate with Lighthouse.
Run Lighthouse audit:
- •Open page in Chrome
- •DevTools → Lighthouse tab
- •Select "Accessibility" category
- •Click "Analyze page load"
Target score: 100/100 (MANDATORY for all HAP Learning Labs)
Common Lighthouse issues caught:
- •Insufficient color contrast
- •Missing form labels
- •Missing ARIA labels on landmarks
- •Images without alt text
- •Empty headings
- •Links without descriptive text
- •Duplicate IDs
If score < 100:
- •Review each failed audit
- •Fix issues in HTML
- •Re-run Lighthouse
- •Repeat until 100/100
Common accessibility mistakes
From Colors project analysis (5 Lighthouse audit cycles):
- •
Missing nav landmark on hub page
- •Issue: Station cards not wrapped in
<nav>element - •Fix: Wrap stations grid with
<nav aria-label="Learning stations">
- •Issue: Station cards not wrapped in
- •
Empty headings
- •Issue:
<h3></h3>tags with no content - •Fix: Add text content, remove heading, or use
aria-hidden="true"
- •Issue:
- •
Missing aria-labels on navigation
- •Issue: Multiple
<nav>elements without descriptive labels - •Fix: Add unique
aria-labelto each nav
- •Issue: Multiple
- •
Insufficient contrast for orange text
- •Issue: Using base
--warm-orangefor normal text - •Fix: Use
--orange-darkestfor normal text,--orange-darkerfor large bold
- •Issue: Using base
- •
Images without width/height
- •Issue: Images cause layout shift (CLS)
- •Fix: Add
widthandheightattributes to ALL images
- •
Missing skip link
- •Issue: Keyboard users must tab through entire nav
- •Fix: Add skip link as first element in body
- •
Color-only status indicators
- •Issue: Success/error shown only with color
- •Fix: Add icons (✅/❌) and text labels
- •
Links without descriptive text
- •Issue: "Click here" or "Read more" links
- •Fix: Use descriptive link text: "Read HAP's guide to color systems"
Testing procedures
Quick accessibility test (2 minutes)
Run before every commit:
- •
Visual scan:
- • All text readable (good contrast)
- • Focus indicators visible when tabbing
- • Images loaded with correct sizing
- •
Keyboard test:
- • Press Tab → Skip link appears
- • Press Enter → Jumps to main content
- • Tab through all interactive elements
- •
DevTools check:
- • Elements → Accessibility pane shows no contrast issues
- • Console has no accessibility warnings
Full accessibility audit (5-10 minutes)
Run before marking station complete:
- •Lighthouse audit: Accessibility category = 100/100
- •Manual WCAG checklist: All items in this Skill checked
- •Screen reader test (optional but recommended):
- •Enable VoiceOver (Mac) or NVDA (Windows)
- •Navigate page with keyboard only
- •Verify all content accessible
Validation example
Scenario: Adding a new HAP note callout
Before committing, check:
- •
Semantic HTML:
html<div class="hap-note-callout"> <img src="[url]" alt="HAP at his laptop" width="100" height="100"> <div class="hap-note-content"> <h3>HAP's Discovery</h3> <p>When Prof. Teeters showed me...</p> </div> </div>- •✅ Image has alt text
- •✅ Image has width/height
- •✅ Heading has text content
- •✅ Using semantic heading (
<h3>)
- •
Color contrast:
- •Content uses
--dark-browntext on gradient background - •Border uses
--warm-orange(decorative only, not text) - •✅ Contrast validated
- •Content uses
- •
Keyboard navigation:
- •Callout is not interactive
- •No keyboard navigation needed
- •✅ N/A
- •
Lighthouse:
- •Re-run after adding callout
- •✅ Still 100/100
Result: Safe to commit ✅
Notes
- •Accessibility is NOT optional — 100/100 Lighthouse score is MANDATORY
- •Colors project required 5 audit cycles due to skipping pre-commit checks
- •Using this Skill prevents 90%+ of accessibility issues before Lighthouse
- •Most common issue: insufficient text contrast (always use approved HAP color variables)
- •Second most common: missing ARIA labels on navigation elements
- •Skip link is often forgotten — it must be FIRST element in body
Skill version: 1.0 Last updated: October 2025 Source: HAP style guide + Colors project accessibility audit results WCAG Level: AA (Level 2.2)