--- name: accessibility description: Audit and improve web accessibility following WCAG 2.2 guidelines. Use when asked to "improve accessibility", "a11y audit", "WCAG compliance", "screen reader support", "keyboard navigation", or "make accessible". license: MIT metadata: author: web-quality-skills version: "1.1" --- # Accessibility (a11y) Comprehensive accessibility guidelines based on WCAG 2.2 and Lighthouse accessibility audits. Goal: make content usable by everyone, including people with disabilities. ## WCAG Principles: POUR | Principle | Description | |-----------|-------------| | **P**erceivable | Content can be perceived through different senses | | **O**perable | Interface can be operated by all users | | **U**nderstandable | Content and interface are understandable | | **R**obust | Content works with assistive technologies | ## Conformance levels | Level | Requirement | Target | |-------|-------------|--------| | **A** | Minimum accessibility | Must pass | | **AA** | Standard compliance | Should pass (legal requirement in many jurisdictions) | | **AAA** | Enhanced accessibility | Nice to have | --- ## Perceivable ### Text alternatives (1.1) **Images require alt text:** ```html Bar chart showing 40% increase in Q3 sales
2024 market trends infographic
``` **Icon buttons need accessible names:** ```html ``` **Visually hidden class:** ```css .visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; } ``` ### Color contrast (1.4.3, 1.4.6) | Text Size | AA minimum | AAA enhanced | |-----------|------------|--------------| | Normal text (< 18px / < 14px bold) | 4.5:1 | 7:1 | | Large text (≥ 18px / ≥ 14px bold) | 3:1 | 4.5:1 | | UI components & graphics | 3:1 | 3:1 | ```css /* ❌ Low contrast (2.5:1) */ .low-contrast { color: #999; background: #fff; } /* ✅ Sufficient contrast (7:1) */ .high-contrast { color: #333; background: #fff; } /* ✅ Focus states need contrast too */ :focus-visible { outline: 2px solid #005fcc; outline-offset: 2px; } ``` **Don't rely on color alone:** ```html
Please enter a valid email address
``` ### Media alternatives (1.2) ```html
Transcript

Full transcript text...

``` --- ## Operable ### Keyboard accessible (2.1) **All functionality must be keyboard accessible:** ```javascript // ❌ Only handles click element.addEventListener('click', handleAction); // ✅ Handles both click and keyboard element.addEventListener('click', handleAction); element.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); handleAction(); } }); ``` **No keyboard traps.** Users must be able to Tab into and out of every component. Use the [modal focus trap pattern](references/A11Y-PATTERNS.md#modal-focus-trap) for dialogs—the native `` element handles this automatically. ### Focus visible (2.4.7) ```css /* ❌ Never remove focus outlines */ *:focus { outline: none; } /* ✅ Use :focus-visible for keyboard-only focus */ :focus { outline: none; } :focus-visible { outline: 2px solid #005fcc; outline-offset: 2px; } /* ✅ Or custom focus styles */ button:focus-visible { box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.5); } ``` ### Focus not obscured (2.4.11) — new in 2.2 When an element receives keyboard focus, it must not be entirely hidden by other author-created content such as sticky headers, footers, or overlapping panels. At Level AAA (2.4.12), no part of the focused element may be hidden. ```css /* ✅ Account for sticky headers when scrolling to focused elements */ :target { scroll-margin-top: 80px; } /* ✅ Ensure focused items clear fixed/sticky bars */ :focus { scroll-margin-top: 80px; scroll-margin-bottom: 60px; } ``` ### Skip links (2.4.1) Provide a skip link so keyboard users can bypass repetitive navigation. See the [skip link pattern](references/A11Y-PATTERNS.md#skip-link) for full markup and styles. ### Target size (2.5.8) — new in 2.2 Interactive targets must be at least **24 × 24 CSS pixels** (AA). Exceptions: inline text links, elements where the browser controls the size, and targets where a 24px circle centered on the bounding box does not overlap another target. ```css /* ✅ Minimum target size */ button, [role="button"], input[type="checkbox"] + label, input[type="radio"] + label { min-width: 24px; min-height: 24px; } /* ✅ Comfortable target size (recommended 44×44) */ .touch-target { min-width: 44px; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; } ``` ### Dragging movements (2.5.7) — new in 2.2 Any action that requires dragging must have a single-pointer alternative (e.g., buttons, inputs). See the [dragging movements pattern](references/A11Y-PATTERNS.md#dragging-movements) for a sortable-list example. ### Timing (2.2) ```javascript // Allow users to extend time limits function showSessionWarning() { const modal = createModal({ title: 'Session Expiring', content: 'Your session will expire in 2 minutes.', actions: [ { label: 'Extend session', action: extendSession }, { label: 'Log out', action: logout } ], timeout: 120000 }); } ``` ### Motion (2.3) ```css /* Respect reduced motion preference */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } } ``` --- ## Understandable ### Page language (3.1.1) ```html

The French word for hello is bonjour.

``` ### Consistent navigation (3.2.3) ```html ``` ### Consistent help (3.2.6) — new in 2.2 If a help mechanism (contact info, chat widget, FAQ link, self-help option) is repeated across multiple pages, it must appear in the **same relative order** each time. Users who rely on consistent placement shouldn't have to hunt for help on every page. ### Form labels (3.3.2) Every input needs a programmatically associated label. See the [form labels pattern](references/A11Y-PATTERNS.md#form-labels) for explicit, implicit, and instructional examples. ### Error handling (3.3.1, 3.3.3) Announce errors to screen readers with `role="alert"` or `aria-live`, set `aria-invalid="true"` on invalid fields, and focus the first error on submit. See the [error handling pattern](references/A11Y-PATTERNS.md#error-handling) for full markup and JS. ### Redundant entry (3.3.7) — new in 2.2 Don't force users to re-enter information they already provided in the same session. Auto-populate from earlier steps, or let users select from previously entered values. Exceptions: security re-confirmation and content that has expired. ```html
Shipping address
``` ### Accessible authentication (3.3.8) — new in 2.2 Login flows must not rely on cognitive function tests (e.g., remembering a password, solving a puzzle) unless at least one of: - A copy-paste or autofill mechanism is available - An alternative method exists (e.g., passkey, SSO, email link) - The test uses object recognition or personal content (AA only; AAA removes this exception) ```html ``` --- ## Robust ### ARIA usage (4.1.2) **Prefer native elements:** ```html
Click me
Option
``` **When ARIA is needed,** use the correct roles and states. See the [ARIA tabs pattern](references/A11Y-PATTERNS.md#aria-tabs) for a complete tablist example. ### Live regions (4.1.3) Use `aria-live` regions to announce dynamic content changes without moving focus. See the [live regions pattern](references/A11Y-PATTERNS.md#live-regions-and-notifications) for markup and a `showNotification()` helper. --- ## Testing checklist ### Automated testing ```bash # Lighthouse accessibility audit npx lighthouse https://example.com --only-categories=accessibility # axe-core npm install @axe-core/cli -g axe https://example.com ``` ### Manual testing - [ ] **Keyboard navigation:** Tab through entire page, use Enter/Space to activate - [ ] **Screen reader:** Test with VoiceOver (Mac), NVDA (Windows), or TalkBack (Android) - [ ] **Zoom:** Content usable at 200% zoom - [ ] **High contrast:** Test with Windows High Contrast Mode - [ ] **Reduced motion:** Test with `prefers-reduced-motion: reduce` - [ ] **Focus order:** Logical and follows visual order - [ ] **Target size:** Interactive elements meet 24×24px minimum See the [screen reader commands reference](references/A11Y-PATTERNS.md#screen-reader-commands) for VoiceOver and NVDA shortcuts. --- ## Common issues by impact ### Critical (fix immediately) 1. Missing form labels 2. Missing image alt text 3. Insufficient color contrast 4. Keyboard traps 5. No focus indicators ### Serious (fix before launch) 1. Missing page language 2. Missing heading structure 3. Non-descriptive link text 4. Auto-playing media 5. Missing skip links ### Moderate (fix soon) 1. Missing ARIA labels on icons 2. Inconsistent navigation 3. Missing error identification 4. Timing without controls 5. Missing landmark regions ## References - [WCAG 2.2 Quick Reference](https://www.w3.org/WAI/WCAG22/quickref/) - [WAI-ARIA Authoring Practices](https://www.w3.org/WAI/ARIA/apg/) - [Deque axe Rules](https://dequeuniversity.com/rules/axe/) - [Web Quality Audit](../web-quality-audit/SKILL.md) - [WCAG criteria reference](references/WCAG.md) - [Accessibility code patterns](references/A11Y-PATTERNS.md)