Skip to main content

wcag-contrast-color-screen-reader

Implements WCAG 2.2 AA color contrast (4.5:1 text, 3:1 UI), semantic HTML landmarks, heading hierarchy, table markup, ARIA naming, live regions, and screen reader optimization for accessible web applications.

설치로 이동

소스 정보

저장소
paulpas/agent-skill-router
최근 소스 활동
2026년 9월 23일 21:59
감지된 SKILL.md 언어
영어
스타
6
포크
0

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
wcag-contrast-color-screen-reader
description
Implements WCAG 2.2 AA color contrast (4.5:1 text, 3:1 UI), semantic HTML landmarks, heading hierarchy, table markup, ARIA naming, live regions, and screen reader optimization for accessible web applications.
license
MIT
compatibility
opencode
metadata
{"version":"1.0.0","domain":"coding","role":"implementation","scope":"implementation","output-format":"code","triggers":"color contrast, wcag accessibility, screen reader optimization, aria labels, semantic html, landmark navigation, heading hierarchy, alt text","related-skills":[],"archetypes":"tactical, diagnostic","anti_triggers":"brainstorming, vague ideation","response_profile":{"verbosity":"low","directive_strength":"high","abstraction_level":"operational"}}
# WCAG 2.2 AA Color Contrast & Screen Reader Optimization Implement color contrast ratios (4.5:1 minimum for normal text, 3:1 for large text and UI components) and semantic HTML structure with ARIA attributes to ensure WCAG 2.2 AA compliance for assistive technology users. ## TL;DR Checklist - [ ] Color contrast verified: 4.5:1 for body text, 3:1 for large text, 3:1 for UI components (WAVE, Axe, Lighthouse) - [ ] Semantic HTML: one `<main>`, `<nav>`, `<header>`, `<footer>`, `<aside>` per page (landmarks) - [ ] Heading hierarchy: `<h1>` once per page, no skipped levels (h1 → h2 → h3, never h1 → h3) - [ ] Tables marked correctly: `<th scope="col|row">`, `<caption>`, `headers` attribute on complex tables - [ ] Icons: `aria-label` on `<span>` icons or alt text on `<img>`; meaningful, not "icon" or "image" - [ ] ARIA naming: follows order (aria-label > aria-labelledby > text content) - [ ] Live regions: `aria-live="polite"` for non-urgent updates, `aria-live="assertive"` for alerts - [ ] Status messages: `role="status"` for messages that should be announced - [ ] Screen reader tested: VoiceOver (macOS), NVDA (Windows), or JAWS --- ## When to Use Use this skill when: - Building or reviewing components that must pass WCAG 2.2 AA conformance - Designing color palettes or applying brand colors to UI - Implementing form controls, buttons, links, or icon-based interactions - Creating data tables, lists, or complex layouts - Building live update regions (notifications, search results, form validation) - Working with screen readers (VoiceOver, NVDA, JAWS) in testing - Retrofitting existing applications to meet accessibility standards - Ensuring color alone does not convey critical information --- ## When NOT to Use Avoid this skill for: - WCAG 2.1 AAA (enhanced contrast 7:1) requirements — that's a separate, stricter standard - Automated color science or color theory deep dives — focus here is accessibility thresholds - Screen reader automation or third-party testing integrations (use Axe, WAVE, Pa11y for those) - PDFs or document accessibility (different standards apply — see PDF/UA) - Video captions or audio descriptions (separate WCAG criteria: 1.2.1, 1.2.2) - Mobile-only app accessibility (native mobile guidelines may differ) --- ## Core Workflow ### 1. Calculate & Verify Color Contrast **Checkpoint:** Before applying any color, measure its contrast ratio against backgrounds and adjacent colors. **Formula:** Contrast Ratio = (L1 + 0.05) / (L2 + 0.05), where L = relative luminance - L = 0.2126 × R + 0.7152 × G + 0.0722 × B (linear RGB 0–1) - If color channel > 0.03928: channel = channel^2.4; else: channel / 12.92 **WCAG 2.2 AA Thresholds:** - **Normal text**: 4.5:1 (body copy, labels, any text < 18px or < 14px bold) - **Large text**: 3:1 (text ≥ 18px or ≥ 14px bold) - **UI components**: 3:1 (buttons, form inputs, borders, focus indicators) - **Icons/graphics**: 3:1 (if conveying information) **Manual Testing (when tool results are unclear):** - Contrast over gradients: Must test the darkest/lightest pixel pair - Contrast with images: Must test lightest + darkest image regions - Hover/focus states: Must meet 3:1 (for non-text contrast) with adjacent color **Tools:** [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/), [Axe DevTools](https://www.deque.com/axe/devtools/), [WAVE](https://wave.webaim.org/), [Lighthouse](https://developers.google.com/web/tools/lighthouse) ### 2. Define Color Tokens with Contrast Built-In **Checkpoint:** Create a color palette where every color variant is paired with minimum contrast text color. All colors in your design system should specify: "This color is ONLY for backgrounds" or "This color is ONLY for text at 4.5:1 on Color X." **Design pattern:** Use `isAccessibleOnBackground()` function or lookup tables to prevent misuse. ### 3. Structure Semantic HTML Landmarks **Checkpoint:** Every page must have exactly one `<main>`, and navigation must be wrapped in `<nav>`. Landmarks allow screen reader users to jump past content: - `<header>` — top banner (logo, title, global nav) - `<nav>` — navigation menu (one per type: main nav, footer nav, sidebar nav) - `<main>` — primary content (one per page) - `<aside>` — tangential content (sidebar, related articles) - `<footer>` — site footer (copyright, links) ### 4. Verify Heading Hierarchy **Checkpoint:** Page starts with `<h1>`, no levels skipped (h1 → h2 → h3, never h1 → h3). Each section must have a heading that announces its topic. Use `<h2>` to start subsections, not `<h3>`. ### 5. Mark Tables Semantically **Checkpoint:** Header cells use `<th scope="col|row">`, data cells use `<td>`. For complex tables: add `id` to headers and `headers` attribute on data cells pointing to multiple headers. ### 6. Label Icons & Images Meaningfully **Checkpoint:** Every icon and image has an `aria-label` or `alt` text that describes its function, not its appearance. Example: ❌ `aria-label="settings icon"` | ✅ `aria-label="account settings"` ### 7. Implement Live Regions for Updates **Checkpoint:** Dynamic content (form validation results, search updates, notifications) must announce to screen readers. Use `aria-live="polite"` for non-urgent updates, `aria-live="assertive"` for urgent alerts. ### 8. Test with Screen Readers **Checkpoint:** Before shipping, test with at least one screen reader: VoiceOver (macOS, iOS), NVDA (Windows), or JAWS (Windows). Read the page top-to-bottom, verify: landmarks are announced, headings make sense, form labels are read, icons are understood, live updates are heard. --- ## Implementation Patterns ### Pattern 1: CSS Color Tokens with Contrast Metadata ```typescript // colors.ts — Design tokens with built-in accessibility guarantees interface ColorToken { hex: string; name: string; luminance: number; // L from contrast formula textColor: "light" | "dark"; // Which text color meets 4.5:1 minContrastRatio: number; // Verified minimum ratio } const colors = { neutral50: { hex: "#F9FAFB", name: "Neutral 50", luminance: 0.98, textColor: "dark", // Use dark text (e.g., #1F2937) minContrastRatio: 12.6, }, neutral900: { hex: "#111827", name: "Neutral 900", luminance: 0.015, textColor: "light", // Use light text (e.g., #F9FAFB) minContrastRatio: 15.5, }, blue500: { hex: "#3B82F6", name: "Blue 500", luminance: 0.18, textColor: "light", // White text at 4.5:1+ minContrastRatio: 5.2, }, red500: { hex: "#EF4444", name: "Red 500", luminance: 0.213, textColor: "light", // Light text for error states minContrastRatio: 4.7, }, } as const; // Helper: Ensure color is used safely function getTextColorForBackground(bgToken: ColorToken): string { const textColor = bgToken.textColor === "light" ? "#FFFFFF" : "#1F2937"; if (bgToken.minContrastRatio < 4.5) { console.warn( `⚠️ Color ${bgToken.name} has only ${bgToken.minContrastRatio.toFixed(2)}:1 contrast. Consider using a darker background.` ); } return textColor; } // Usage: Safe color application const buttonBg = colors.blue500; const buttonText = getTextColorForBackground(buttonBg); // Result: buttonText = "#FFFFFF" (guaranteed 5.2:1 contrast) ``` **Why This Pattern:** - Contrast is verified once (at token definition), then reused everywhere - No designer can accidentally pair a 2:1 contrast color combination - Warnings catch misuse at runtime --- ### Pattern 2: Semantic HTML Page Structure with Landmarks ```html <!-- Complete WCAG 2.2 AA page structure --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Product Dashboard — MyApp</title> </head> <body> <!-- LANDMARK 1: Header with branding --> <header role="banner" aria-label="Site header"> <div class="header-content"> <a href="/" class="logo" aria-label="MyApp home"> <img src="logo.svg" alt="MyApp" /> </a> <!-- LANDMARK 2: Primary navigation --> <nav aria-label="Main navigation"> <ul> <li> <a href="/dashboard" aria-current="page">Dashboard</a> </li> <li><a href="/analytics">Analytics</a></li> <li><a href="/settings">Settings</a></li> </ul> </nav> </div> </header> <div class="page-layout"> <!-- LANDMARK 3: Sidebar navigation (secondary) --> <aside aria-label="Sidebar navigation"> <nav aria-label="Filters"> <fieldset> <legend>Filter by status</legend> <label> <input type="checkbox" name="status" value="active" /> Active </label> <label> <input type="checkbox" name="status" value="pending" /> Pending </label> </fieldset> </nav> </aside> <!-- LANDMARK 4: Main content area (only one per page) --> <main id="main-content" aria-label="Dashboard content"> <!-- Section with heading hierarchy --> <h1>Sales Dashboard</h1> <!-- Key metrics section --> <section aria-labelledby="metrics-heading"> <h2 id="metrics-heading">Q4 Metrics</h2> <!-- Grid of metric cards with proper ARIA --> <div class="metrics-grid"> <article class="metric-card"> <h3>Total Revenue</h3> <p class="metric-value" aria-label="Total revenue: 124 thousand dollars"> $124K </p> <p class="metric-change" aria-label="increase of 12 percent"> ↑ 12% </p> </article> <article class="metric-card"> <h3>Active Users</h3> <p class="metric-value" aria-label="Active users: 3 thousand 420"> 3.4K </p> <p class="metric-change" aria-label="increase of 8 percent"> ↑ 8% </p> </article> </div> </section> <!-- Data table with accessibility markup --> <section aria-labelledby="table-heading"> <h2 id="table-heading">Recent Orders</h2> <table> <caption>Orders from the past 7 days, sorted by date</caption> <thead> <tr> <th scope="col">Order ID</th> <th scope="col">Customer</th> <th scope="col">Total</th> <th scope="col">Status</th> <th scope="col">Action</th> </tr> </thead> <tbody> <tr> <td>ORD-001</td> <td>Alice Smith</td> <td>$2,500</td> <td> <span class="badge badge-completed" role="status" aria-label="Completed" > Completed </span> </td> <td> <button aria-label="View order ORD-001 details">View</button> </td> </tr> <tr> <td>ORD-002</td> <td>Bob Johnson</td> <td>$1,200</td> <td> <span class="badge badge-pending" role="status" aria-label="Pending" > Pending </span> </td> <td> <button aria-label="View order ORD-002 details">View</button> </td> </tr> </tbody> </table> </section> <!-- Live region for dynamic updates --> <div id="search-results" aria-live="polite" aria-label="Search results" role="status" > <!-- JavaScript updates this area; screen readers announce changes --> </div> </main> </div> <!-- LANDMARK 5: Footer --> <footer role="contentinfo" aria-label="Site footer"> <nav aria-label="Footer navigation"> <ul> <li><a href="/privacy">Privacy Policy</a></li> <li><a href="/terms">Terms of Service</a></li> <li><a href="/accessibility">Accessibility</a></li> </ul> </nav> <p>&copy; 2026 MyApp, Inc. All rights reserved.</p> </footer> </body>
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기