334 lines
8.1 KiB
Markdown
334 lines
8.1 KiB
Markdown
# Patterns: Accessibility
|
||
|
||
Patterns for ensuring interfaces are usable by everyone.
|
||
|
||
---
|
||
|
||
## Why Accessibility Matters
|
||
|
||
- **Legal** — ADA, Section 508, WCAG compliance requirements
|
||
- **Ethical** — Equal access is a design responsibility
|
||
- **Business** — 15%+ of users have some disability
|
||
- **Quality** — Accessible design improves UX for everyone
|
||
|
||
**Core principle:** Accessibility is not a checklist item—it's a design approach.
|
||
|
||
---
|
||
|
||
## Keyboard Navigation
|
||
|
||
**What:** Full functionality without a mouse.
|
||
|
||
### Requirements
|
||
|
||
| Pattern | Keyboard Support |
|
||
|---------|------------------|
|
||
| **Focus order** | Tab moves logically through page |
|
||
| **Focus visible** | Current focus always visible |
|
||
| **Activation** | Enter/Space activates buttons/links |
|
||
| **Navigation** | Arrow keys navigate within components |
|
||
| **Escape** | Escape closes modals/popups |
|
||
| **Shortcuts** | Common shortcuts available |
|
||
|
||
### Focus Order Principles
|
||
|
||
1. Follow visual reading order (left-to-right, top-to-bottom)
|
||
2. Skip decorative/non-interactive elements
|
||
3. Group related controls
|
||
4. Don't trap focus (except in modals)
|
||
5. Return focus appropriately after interactions
|
||
|
||
### Implementation Guidelines
|
||
|
||
**DO:**
|
||
- Use semantic HTML (inherits keyboard support)
|
||
- Provide visible focus indicators (not outline: none)
|
||
- Test with keyboard only
|
||
- Support standard keyboard patterns
|
||
- Announce changes to screen readers
|
||
|
||
**DON'T:**
|
||
- Use div/span for interactive elements (without ARIA)
|
||
- Remove focus outlines without replacement
|
||
- Create custom interactions without keyboard support
|
||
- Change focus order unpredictably
|
||
- Trap users in infinite tab loops
|
||
|
||
### Focus Indicator Styling
|
||
|
||
```css
|
||
/* Visible, high contrast focus */
|
||
:focus-visible {
|
||
outline: 2px solid #2563eb;
|
||
outline-offset: 2px;
|
||
}
|
||
|
||
/* Remove default only when custom is applied */
|
||
button:focus {
|
||
outline: none;
|
||
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.5);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## ARIA Attributes
|
||
|
||
**What:** Accessible Rich Internet Applications—additional semantics for assistive technology.
|
||
|
||
### Core ARIA Rules
|
||
|
||
1. **First rule:** Don't use ARIA if native HTML works
|
||
2. **Second rule:** Don't change native semantics
|
||
3. **Third rule:** All interactive ARIA must be keyboard accessible
|
||
4. **Fourth rule:** Don't use role="presentation" on focusable elements
|
||
5. **Fifth rule:** All interactive elements must have accessible names
|
||
|
||
### Essential ARIA Attributes
|
||
|
||
| Attribute | Purpose | Example |
|
||
|-----------|---------|---------|
|
||
| `aria-label` | Accessible name | `<button aria-label="Close">×</button>` |
|
||
| `aria-describedby` | Additional description | Links to help text |
|
||
| `aria-hidden` | Hide from assistive tech | Decorative elements |
|
||
| `aria-expanded` | Toggle state | Accordions, dropdowns |
|
||
| `aria-selected` | Selection state | Tabs, list items |
|
||
| `aria-live` | Announce changes | Dynamic content |
|
||
| `aria-invalid` | Invalid state | Form validation |
|
||
| `aria-required` | Required field | Form fields |
|
||
|
||
### Common Patterns
|
||
|
||
**Button with icon only:**
|
||
```html
|
||
<button aria-label="Delete item">
|
||
<svg aria-hidden="true">...</svg>
|
||
</button>
|
||
```
|
||
|
||
**Accordion:**
|
||
```html
|
||
<button aria-expanded="false" aria-controls="panel1">
|
||
Section Title
|
||
</button>
|
||
<div id="panel1" hidden>Content...</div>
|
||
```
|
||
|
||
**Live region:**
|
||
```html
|
||
<div aria-live="polite" aria-atomic="true">
|
||
<!-- Content changes announced by screen reader -->
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
## Alternative Text
|
||
|
||
**What:** Text equivalents for non-text content.
|
||
|
||
### Alt Text Guidelines
|
||
|
||
**Informative images:**
|
||
- Describe the content/function
|
||
- Be concise but complete
|
||
- Don't include "image of" or "picture of"
|
||
|
||
**Decorative images:**
|
||
- Use empty alt: `alt=""`
|
||
- Or use `aria-hidden="true"`
|
||
|
||
**Functional images (buttons/links):**
|
||
- Describe the action, not the image
|
||
- "Submit form" not "arrow icon"
|
||
|
||
**Complex images:**
|
||
- Provide detailed description nearby
|
||
- Use `aria-describedby` to link
|
||
- Consider data tables for charts
|
||
|
||
### Examples
|
||
|
||
| Image | Bad Alt | Good Alt |
|
||
|-------|---------|----------|
|
||
| Logo | "Logo" | "Acme Corp" |
|
||
| Search icon | "Magnifying glass" | "Search" |
|
||
| Product photo | "Photo" | "Blue cotton t-shirt, front view" |
|
||
| Decorative border | "Border" | `alt=""` (empty) |
|
||
| Chart | "Chart" | "Sales increased 25% from Q1 to Q2" + full data table |
|
||
|
||
---
|
||
|
||
## Color & Contrast
|
||
|
||
**What:** Ensuring content is perceivable regardless of color vision.
|
||
|
||
### Contrast Requirements
|
||
|
||
| Content | Minimum Ratio | Target Ratio |
|
||
|---------|---------------|--------------|
|
||
| Normal text | 4.5:1 | 7:1 (AAA) |
|
||
| Large text (18px+) | 3:1 | 4.5:1 (AAA) |
|
||
| UI components | 3:1 | 4.5:1 |
|
||
| Focus indicators | 3:1 | 4.5:1 |
|
||
|
||
### Color Guidelines
|
||
|
||
**DO:**
|
||
- Use high contrast combinations
|
||
- Include patterns/icons in addition to color
|
||
- Test with color blindness simulators
|
||
- Provide color contrast alternatives
|
||
- Verify with automated tools
|
||
|
||
**DON'T:**
|
||
- Use color as the only indicator
|
||
- Use low contrast text
|
||
- Place colored text on similar backgrounds
|
||
- Assume everyone sees the same colors
|
||
- Use red/green as the only differentiator
|
||
|
||
### Color + Pattern Example
|
||
|
||
```
|
||
✓ Success (green check icon + green color)
|
||
✗ Error (red X icon + red color + border)
|
||
! Warning (yellow triangle icon + yellow background)
|
||
```
|
||
|
||
---
|
||
|
||
## Text & Readability
|
||
|
||
**What:** Ensuring text is readable by all users.
|
||
|
||
### Guidelines
|
||
|
||
**Font size:**
|
||
- Minimum 16px for body text
|
||
- Support browser zoom up to 200%
|
||
- Use relative units (rem, em)
|
||
|
||
**Line length:**
|
||
- 45-75 characters per line
|
||
- Max-width on text containers
|
||
|
||
**Line height:**
|
||
- 1.5 minimum for body text
|
||
- 1.2 minimum for headings
|
||
|
||
**Font choice:**
|
||
- Sans-serif for UI
|
||
- Avoid decorative fonts for body
|
||
- Adequate x-height
|
||
|
||
**Text resizing:**
|
||
- Content must remain usable at 200% zoom
|
||
- No horizontal scrolling at 320px width
|
||
|
||
---
|
||
|
||
## Interactive Elements
|
||
|
||
**What:** Making interactive elements accessible.
|
||
|
||
### Minimum Sizes
|
||
|
||
| Element | Minimum Size | Target Size |
|
||
|---------|--------------|-------------|
|
||
| Touch targets | 44x44px | 48x48px |
|
||
| Click targets | 24x24px | 32x32px |
|
||
| Spacing between | 8px | 12px |
|
||
|
||
### Element Guidelines
|
||
|
||
**Links:**
|
||
- Descriptive text (not "click here")
|
||
- Distinguish from regular text
|
||
- Show visited state
|
||
- Focus + hover states
|
||
|
||
**Buttons:**
|
||
- Clear labels
|
||
- Sufficient size
|
||
- Visible states (hover, focus, active, disabled)
|
||
- Keyboard accessible
|
||
|
||
**Forms:**
|
||
- Labels associated with inputs
|
||
- Error messages linked (aria-describedby)
|
||
- Required fields indicated
|
||
- Group related fields (fieldset/legend)
|
||
|
||
---
|
||
|
||
## Motion & Animation
|
||
|
||
**What:** Respecting user preferences for reduced motion.
|
||
|
||
### Guidelines
|
||
|
||
**DO:**
|
||
- Respect `prefers-reduced-motion`
|
||
- Keep animations subtle
|
||
- Allow users to pause/stop animations
|
||
- Avoid flashing content (seizure risk)
|
||
|
||
**DON'T:**
|
||
- Auto-play video with motion
|
||
- Use fast/flashing animations
|
||
- Create vestibular triggers
|
||
- Force users to watch animations
|
||
|
||
### Implementation
|
||
|
||
```css
|
||
@media (prefers-reduced-motion: reduce) {
|
||
* {
|
||
animation: none !important;
|
||
transition: none !important;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Screen Reader Testing
|
||
|
||
**What:** Verifying experience for screen reader users.
|
||
|
||
### Testing Checklist
|
||
|
||
☐ All images have appropriate alt text
|
||
☐ Headings create logical outline (H1 → H2 → H3)
|
||
☐ Links and buttons have descriptive names
|
||
☐ Form labels are associated with inputs
|
||
☐ Error messages are announced
|
||
☐ Dynamic content changes are announced
|
||
☐ Focus management works after interactions
|
||
☐ Page title is descriptive
|
||
|
||
### Screen Readers to Test
|
||
|
||
- **VoiceOver** — macOS/iOS (built-in)
|
||
- **NVDA** — Windows (free)
|
||
- **JAWS** — Windows (paid, enterprise standard)
|
||
- **TalkBack** — Android (built-in)
|
||
|
||
---
|
||
|
||
## Accessibility Checklist
|
||
|
||
| Category | Requirements |
|
||
|----------|--------------|
|
||
| ☐ **Keyboard** | All functions keyboard accessible |
|
||
| ☐ **Focus** | Visible focus indicators |
|
||
| ☐ **Semantics** | Proper HTML elements + ARIA |
|
||
| ☐ **Images** | Alt text for all meaningful images |
|
||
| ☐ **Color** | Not the only differentiator |
|
||
| ☐ **Contrast** | 4.5:1 for text, 3:1 for UI |
|
||
| ☐ **Text** | Resizable, readable, proper hierarchy |
|
||
| ☐ **Motion** | Reducible, not seizure-inducing |
|
||
| ☐ **Forms** | Labels, errors, required indicators |
|
||
| ☐ **Testing** | Verified with screen reader |
|