用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/skeletorflet/opencode-kit --skill accessibility命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | accessibility |
| description | Web accessibility (a11y). WCAG 2.1, ARIA, keyboard navigation, screen readers, testing tools. |
Accessible apps are better apps for everyone.
| Principle | Meaning |
|---|---|
| Perceivable | Info must be presentable to all senses |
| Operable | UI must be keyboard + assistive tech operable |
| Understandable | Content and operation must be comprehensible |
| Robust | Must work with current + future assistive tech |
Target: AA conformance (minimum for most products)
| Element | Minimum Ratio | AA+ Ratio |
|---|---|---|
| Normal text (< 18px) | 4.5:1 | 7:1 |
| Large text (≥ 18px) | 3:1 | 4.5:1 |
| UI components (borders, icons) | 3:1 | — |
| Disabled state | No requirement | — |
Tools:
├── WebAIM Contrast Checker
├── Chrome DevTools → Accessibility panel
└── axe DevTools browser extension
\x3C!-- ❌ Bad -->
<div class="button" onclick="submit()">Submit</div>
<div class="heading">Section Title</div>
<div class="nav">...</div>
\x3C!-- ✅ Good -->
<button type="submit">Submit</button>
<h2>Section Title</h2>
<nav aria-label="Main navigation">...</nav>
\x3C!-- When to use ARIA:
Rule 1: Don\'t use ARIA if native HTML works
Rule 2: Don\'t change native semantics unnecessarily
Rule 3: All interactive ARIA controls must be keyboard-focusable -->
\x3C!-- Modal Dialog -->
<div role="dialog" aria-modal="true" aria-labelledby="modal-title" aria-describedby="modal-desc">
<h2 id="modal-title">Confirm Delete</h2>
<p id="modal-desc">This action cannot be undone.</p>
<button>Cancel</button>
<button>Delete</button>
</div>
\x3C!-- Live Region (dynamic content) -->
<div aria-live="polite" aria-atomic="true">
\x3C!-- Updates announced to screen readers -->
{statusMessage}
</div>
\x3C!-- Icon button -->
<button aria-label="Close dialog">
<svg aria-hidden="true">...</svg>
</button>
\x3C!-- Loading -->
<div role= =>
| Key | Expected Behavior |
|---|---|
Tab | Move to next focusable element |
Shift+Tab | Move to previous |
Enter / Space | Activate button/link |
Escape | Close modal/dropdown |
| Arrow keys | Navigate within widget (menu, tabs, listbox) |
// Focus trap (modals)
import { useFocusTrap } from "@mantine/hooks"; // or write custom
function Modal({ isOpen, onClose, children }) {
const focusTrapRef = useFocusTrap(isOpen);
return isOpen ? (
<div ref={focusTrapRef} role="dialog" aria-modal="true">
{children}
</div>
) : null;
}
// Skip link (keyboard shortcut to main content)
<a href="#main-content" className="sr-only focus:not-sr-only">
Skip to main content
</a>
\x3C!-- Informative image -->
<img src="chart.png" alt="Bar chart showing 40% increase in Q4 revenue" />
\x3C!-- Decorative image -->
<img src="divider.png" alt="" role="presentation" />
\x3C!-- Icon (standalone meaning) -->
<svg aria-label="Settings" role="img">...</svg>
\x3C!-- Video -->
<video>
<track kind="captions" src="captions.vtt" srclang="en" label="English" />
</video>
\x3C!-- Always associate label with input -->
<label for="email">Email address</label>
<input id="email" type="email" required
aria-describedby="email-hint email-error"
aria-invalid="true" />
<span id="email-hint">We\'ll never share your email.</span>
<span id="email-error" role="alert">Please enter a valid email.</span>
\x3C!-- Fieldset for groups -->
<fieldset>
<legend>Notification preferences</legend>
<label><input type="checkbox" name="email"> Email</label>
<label><input type="checkbox" name="sms"> SMS</label>
</fieldset>
| Tool | Type | Use For |
|---|---|---|
| axe DevTools | Browser ext | Automated scan |
| Lighthouse | Chrome DevTools | Audit score |
| NVDA | Screen reader (Windows) | Manual testing |
| VoiceOver | Screen reader (Mac/iOS) | Manual testing |
| jest-axe | Unit test | CI/CD integration |
| Playwright | E2E | Keyboard/focus testing |
// jest-axe
import { axe, toHaveNoViolations } from "jest-axe";
expect.extend(toHaveNoViolations);
it("has no accessibility violations", async () => {
const { container } = render(<MyForm />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
outline: none)<h1>, logical heading hierarchy