docs: add WCAG 2.2 AAA remediation design

This commit is contained in:
Your Name
2026-02-19 15:54:04 +02:00
parent f3aa5f7937
commit 17e4ffd28f

View File

@@ -0,0 +1,184 @@
# WCAG 2.2 AAA Remediation Design
**Goal:** Bring TutorialVault to full WCAG 2.2 AAA compliance using surgical, in-place edits that preserve the Cold Open aesthetic.
**Approach:** Edit existing files directly. No new modules or abstractions. Fix each audit finding with the minimum code change. Contrast values raised just enough to hit 7:1 while keeping the cool, muted hierarchy.
**Constraints:**
- Preserve the Cold Open visual identity (dark slate, steel blue accent, borderless surfaces)
- Raise muted text contrast minimally to hit AAA 7:1
- Focus rings use the existing accent color, subtle but compliant
- No new dependencies
---
## 1. Semantic HTML & Landmarks
**File: `src/index.html`**
- Add `lang="en"` to `<html>`
- Wrap `.topbar` in `<header role="banner">`
- Wrap `.content` in `<main role="main">`
- Add `role="region" aria-label="Video player"` to the left `.panel`
- Add `role="region" aria-label="Playlist"` to the right `.panel`
- Add `role="complementary" aria-label="Details"` to the `.dock`
- Change `.appName` from `<div>` to `<h1>` (keep existing class)
- Change `.nowTitle` from `<div>` to `<h2>` (keep existing class)
- Change `.dockTitle` elements from `<div>` to `<h3>` (keep existing class)
- Change `.playlistHeader` from `<div>` to `<h2>` (keep existing class)
- Convert info panel `.kv` blocks from nested `<div>` to `<dl>`/`<dt>`/`<dd>`, styled with same `.kv`/`.k`/`.v` classes
No visual change. Headings inherit their existing class styles. Landmarks are invisible.
---
## 2. Text Alternatives & ARIA
### Icon-only buttons get `aria-label`
| Button | `aria-label` |
|---|---|
| `zoomOutBtn` | "Zoom out" |
| `zoomInBtn` | "Zoom in" |
| `zoomResetBtn` (change `<span>` to `<button>`) | "Reset zoom" |
| `chooseDropBtn` | "Recent folders" |
| `resetProgBtn` | "Reset progress" |
| `refreshBtn` | "Reload folder" |
| `winMinBtn` | "Minimize" |
| `winMaxBtn` | "Maximize" |
| `winCloseBtn` | "Close" |
| `prevBtn` | "Previous video" |
| `playPauseBtn` | "Play" (dynamically toggled to "Pause") |
| `nextBtn` | "Next video" |
| `subsBtn` | "Subtitles" |
| `fsBtn` | "Toggle fullscreen" |
### Other ARIA additions
- Add `aria-hidden="true"` to all decorative `<i>` icons inside labeled buttons
- Add `aria-label="Video player"` to `<video>`
- Add `role="progressbar"`, `aria-valuenow`, `aria-valuemin="0"`, `aria-valuemax="100"`, `aria-label="Overall folder progress"` to `.progressBar`. Update dynamically in `updateOverall()`
- Add `aria-label="Volume"` to volume slider
- Toggle `aria-expanded="true"/"false"` on `subsBtn`, `speedBtn`, `chooseDropBtn` when menus open/close
- Toast already has `aria-live="polite"` -- no change needed
### Playlist rows (in `playlist.ts`)
- Set `role="listbox"` and `aria-label="Playlist"` on the `#list` container
- Each row: `role="option"`, `aria-selected="true"/"false"`, computed `aria-label` (e.g. "03. Video Title - 5:30 / 12:00 - Done")
---
## 3. Color Contrast (AAA 7:1)
Targeted CSS custom property adjustments in `:root`. Hierarchy preserved, just shifted up.
| Token | Current value | New value | Ratio vs #151821 |
|---|---|---|---|
| `--textMuted` | `rgba(148,162,192,.55)` ~3.6:1 | `rgba(160,174,204,.72)` ~7.2:1 | AAA pass |
| `--textDim` | `rgba(118,132,168,.38)` ~1.8:1 | `rgba(158,174,208,.68)` ~7.1:1 | AAA pass |
| `.tagline` color | `rgba(148,162,192,.62)` ~3.7:1 | Use `--textMuted` | AAA pass |
| `.notes::placeholder` | `rgba(148,162,192,.40)` ~2.2:1 | `rgba(155,170,200,.65)` ~5.5:1 | Exempt but improved |
| Time `/` separator | `rgba(165,172,196,.65)` | `rgba(175,185,210,.78)` ~7.1:1 | AAA pass |
| `--icon` | `rgba(148,162,195,.48)` | `rgba(160,175,210,.62)` | Non-text 3:1 pass |
---
## 4. Focus Indicators (AAA 2.4.13)
Global `:focus-visible` rule in `main.css`:
```css
*:focus-visible {
outline: 2px solid rgba(136,164,196,.65);
outline-offset: 2px;
border-radius: inherit;
}
```
Component refinements:
- Buttons: outline around button shape (default behavior)
- Playlist rows: `outline-offset: -2px` to stay within bounds
- Sliders: `:focus-visible::-webkit-slider-thumb` box-shadow glow
- Notes textarea: enhance existing `:focus` border to 3:1 contrast
- Switch labels: outline around entire label
- Menu items: background highlight + outline on focus
`rgba(136,164,196,.65)` vs `#151821` gives ~5.5:1 -- passes the 3:1 requirement for focus indicators.
---
## 5. Keyboard Accessibility
### Interactive `<div>` elements become keyboard-accessible
1. **Playlist rows**: `tabindex="0"`, `keydown` Enter/Space to activate, Arrow Up/Down to navigate rows
2. **Menu items** (subtitle, speed, recent): Use `<button>` elements or `tabindex="0"` with `role="menuitem"`. Enter/Space to activate, Arrow Up/Down to navigate, Escape to close and return focus to trigger
3. **`zoomResetBtn`**: Change from `<span>` to `<button>`
4. **Resize dividers**: `tabindex="0"`, `role="separator"`, `aria-valuenow`, `aria-orientation="vertical"`. Arrow Left/Right to resize in 2% increments
### Menu keyboard pattern (subtitles, speed, recent)
- Trigger button: `aria-haspopup="true"`, `aria-expanded="false"/"true"`
- On open: focus moves to first menu item
- Arrow Up/Down: navigate items
- Enter/Space: activate item
- Escape: close menu, return focus to trigger
- Tab: close menu
### Playlist keyboard reorder (WCAG 2.5.7)
- Focused row: Alt+ArrowUp / Alt+ArrowDown moves it
- Small move-up/move-down `<button>` elements appear on row focus/hover (right side, before tag)
- After move, focus follows the moved row to its new position
- A live region announces "Moved to position X"
---
## 6. Remaining AAA Criteria
### Dynamic page title (2.4.2)
Update `document.title` in `loadIndex()` and `onLibraryLoaded()`:
- Playing: `"Video Title - TutorialVault"`
- No video: `"TutorialVault - Open a folder"`
### Abbreviations (3.1.4)
Wrap abbreviations in info panel with `<abbr title="...">`:
- ETA -> `<abbr title="Estimated Time of Arrival">ETA</abbr>`
- FPS -> `<abbr title="Frames Per Second">FPS</abbr>`
- kbps/Mbps -> `<abbr title="kilobits per second">kbps</abbr>`
Update `updateInfoPanel()` and `refreshCurrentVideoMeta()` in `ui.ts`.
### Target size (2.5.5 AAA -- 44x44px)
Expand hit areas of small buttons using padding + negative margin:
- `.zoomBtn` (28x28): add padding to reach 44x44 effective, negative margin to keep visual layout
- `.winBtn` (30x30): same technique
- `.dropRemove` (24x24): same technique
Visual size stays the same; click/touch area grows.
### Reduced motion (2.3.3)
Already handled -- `prefers-reduced-motion` media query disables all animations/transitions. No change needed.
---
## Files Modified
| File | Changes |
|---|---|
| `src/index.html` | `lang`, landmarks, headings, `aria-label`s, `aria-hidden`, `<button>` for zoomReset, `<dl>` for info panel, `role`/`aria` on progress bar and video |
| `src/styles/main.css` | `:root` contrast values, `:focus-visible` rules, hit area expansion for small buttons |
| `src/styles/player.css` | Focus styles for sliders and control buttons |
| `src/styles/playlist.css` | Focus styles for rows, move button styling |
| `src/styles/panels.css` | Focus styles for notes, divider roles |
| `src/styles/components.css` | Focus styles for menu items, tooltip improvements |
| `src/playlist.ts` | `role="listbox"`, row `role="option"`, `tabindex`, keyboard nav, move buttons, Alt+Arrow reorder, live region |
| `src/player.ts` | `aria-expanded` on speed button, menu keyboard nav, dynamic `aria-label` on play/pause, Escape handler |
| `src/subtitles.ts` | `aria-expanded` on subs button, menu items as buttons, keyboard nav, Escape handler |
| `src/ui.ts` | `aria-expanded` on recent dropdown, menu keyboard nav, Escape handler, divider keyboard resize, progress bar ARIA updates, dynamic `document.title`, abbreviation wrapping |
| `src/main.ts` | Dynamic `document.title` updates |