wcag-audit-patterns について
WCAG 2.2 に基づいてウェブコンテンツを監査し、修正を計画するためのリファレンススキルです。開発者やアクセシビリティのレビュー担当者向けに、チェックリスト、コード例、自動テストの指針を提供します。
主な機能
- 01WCAG 適合レベルと POUR 原則
- 02アクセシビリティ基準別の監査チェックリスト
- 03よくある問題と修正パターン
- 04axe-core と Playwright のテスト例
- 05アクセシビリティ検査コマンドの例
活用シーン
- 01ウェブサイトの WCAG 問題の確認
- 02フォームラベルやキーボード操作の修正計画
- 03Playwright テストへのアクセシビリティ検査追加
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ marcioaltoe/ skills --skill wcag-audit-patternsインストール後、Claude Code で/wcag-audit-patternsを入力して読み込まれたか確認します。
同梱ファイルagents/openai.yaml
詳細
WCAG 監査パターン
WCAG 2.2 ガイドラインに照らしてウェブコンテンツを監査し、実行可能な修正方法を示す包括的なガイドです。
このスキルを使用する場面
- アクセシビリティ監査を実施する
- WCAG 違反を修正する
- アクセシブルなコンポーネントを実装する
- アクセシビリティ関連の訴訟に備える
- ADA/Section 508 の要件を満たす
- VPAT 準拠を達成する
主な概念
1. WCAG 適合レベル
| レベル | 説明 | 必要とされる対象 |
|---|---|---|
| A | 最低限のアクセシビリティ | 法的な最低基準 |
| AA | 標準的な適合性 | ほとんどの規制 |
| AAA | 高度なアクセシビリティ | 特殊なニーズ |
2. POUR の原則
Perceivable: Can users perceive the content?
Operable: Can users operate the interface?
Understandable: Can users understand the content?
Robust: Does it work with assistive tech?
3. 影響度別のよくある違反
Critical (Blockers):
├── Missing alt text for functional images
├── No keyboard access to interactive elements
├── Missing form labels
└── Auto-playing media without controls
Serious:
├── Insufficient color contrast
├── Missing skip links
├── Inaccessible custom widgets
└── Missing page titles
Moderate:
├── Missing language attribute
├── Unclear link text
├── Missing landmarks
└── Improper heading hierarchy
監査チェックリスト
知覚可能(原則 1)
## 1.1 Text Alternatives
### 1.1.1 Non-text Content (Level A)
- [ ] All images have alt text
- [ ] Decorative images have alt=""
- [ ] Complex images have long descriptions
- [ ] Icons with meaning have accessible names
- [ ] CAPTCHAs have alternatives
Check:
```html
<img src="chart.png" alt="Sales increased 25% from Q1 to Q2" />
<img src="decorative-line.png" alt="" />
<img src="chart.png" />
<img src="decorative-line.png" alt="decorative line" />
```
1.2 時間依存メディア
1.2.1 音声のみおよび映像のみ(レベル A)
- 音声にテキストの書き起こしがある
- 映像に音声解説または書き起こしがある
1.2.2 キャプション(レベル A)
- すべての映像に同期したキャプションがある
- キャプションが正確で完全である
- 話者の識別情報が含まれている
1.2.3 音声解説(レベル A)
- 映像に視覚的なコンテンツの音声解説がある
1.3 適応可能
1.3.1 情報と関係性(レベル A)
- 見出しに適切なタグ(h1-h6)を使用している
- リストに ul/ol/dl を使用している
- テーブルに見出しがある
- フォームの入力欄にラベルがある
- ARIA ランドマークがある
確認項目:
<h1>Page Title</h1>
<h2>Section</h2>
<h3>Subsection</h3>
<h2>Another Section</h2>
<table>
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Price</th>
</tr>
</thead>
</table>
1.3.2 意味のある順序(レベル A)
- 読み上げ順序が論理的である
- CSS による配置で順序が崩れていない
- フォーカス順序が視覚的な順序と一致している
1.3.3 感覚的な特徴(レベル A)
- 指示が形や色だけに依存していない
- 「赤いボタンをクリック」→「送信(赤いボタン)をクリック」
1.4 識別可能
1.4.1 色の使用(レベル A)
- 情報を伝える手段が色だけではない
- リンクが色以外の方法でも識別できる
- エラー状態が色だけで示されていない
ツール:WebAIM Contrast Checker、axe DevTools
1.4.3 コントラスト(最低限)(レベル AA)
- テキスト:コントラスト比 4.5:1
- 大きなテキスト(18pt 以上):比率 3:1
- UI コンポーネント:比率 3:1
1.4.4 テキストのサイズ変更(レベル AA)
- 情報を失わずにテキストを 200% まで拡大できる
- 幅 320px で横スクロールが発生しない
- コンテンツが適切にリフローする
1.4.10 リフロー(レベル AA)
- 400% ズームでコンテンツがリフローする
- 2 次元スクロールが発生しない
- 幅 320px ですべてのコンテンツにアクセスできる
1.4.11 非テキストのコントラスト(レベル AA)
- UI コンポーネントのコントラスト比が 3:1 である
- フォーカスインジケーターが見える
- グラフィックオブジェクトを識別できる
1.4.12 テキスト間隔(レベル AA)
- 間隔を広げてもコンテンツが失われない
- 行の高さがフォントサイズの 1.5 倍である
- 段落の間隔がフォントサイズの 2 倍である
- 文字間隔がフォントサイズの 0.12 倍である
- 単語間隔がフォントサイズの 0.16 倍である
### Operable (Principle 2)
```markdown
## 2.1 Keyboard Accessible
### 2.1.1 Keyboard (Level A)
- [ ] All functionality keyboard accessible
- [ ] No keyboard traps
- [ ] Tab order is logical
- [ ] Custom widgets are keyboard operable
Check:
```javascript
// Custom button must be keyboard accessible
<div role="button" tabindex="0"
onkeydown="if(event.key === 'Enter' || event.key === ' ') activate()">
2.1.2 キーボードトラップなし(レベル A)
- すべてのコンポーネントからフォーカスを移動できる
- モーダルダイアログでフォーカスが適切にトラップされる
- モーダルを閉じた後にフォーカスが戻る
2.2 十分な時間
2.2.1 時間調整可能(レベル A)
- セッションのタイムアウトを延長できる
- タイムアウト前にユーザーに警告する
- 自動更新を無効にするオプションがある
2.2.2 一時停止、停止、非表示(レベル A)
- 動きのあるコンテンツを一時停止できる
- 自動更新するコンテンツを一時停止できる
- アニメーションが prefers-reduced-motion を尊重する
@media (prefers-reduced-motion: reduce) {
* {
animation: none !important;
transition: none !important;
}
}
2.3 発作および身体的反応
2.3.1 3 回の閃光(レベル A)
- 1 秒間に 3 回を超えて点滅するコンテンツがない
- 点滅する領域が小さい(ビューポートの 25% 未満)
2.4 ナビゲーション可能
2.4.1 ブロックの回避(レベル A)
- メインコンテンツへのスキップリンクがある
- ランドマーク領域が定義されている
- 見出し構造が適切である
<a href="#main" class="skip-link">Skip to main content</a>
<main id="main">...</main>
2.4.2 ページタイトル(レベル A)
- ページタイトルが一意で、内容を説明している
- タイトルがページの内容を反映している
2.4.3 フォーカス順序(レベル A)
- フォーカス順序が視覚的な順序と一致している
- tabindex が正しく使用されている
2.4.4 リンクの目的(文脈内)(レベル A)
- リンクは文脈から切り離しても意味が通じる
- 「ここをクリック」や「続きを読む」だけのリンクにしない
<a href="report.pdf">Click here</a>
<a href="report.pdf">Download Q4 Sales Report (PDF)</a>
2.4.6 見出しとラベル(レベル AA)
- 見出しは内容を説明している
- ラベルは目的を説明している
2.4.7 フォーカスの可視化(レベル AA)
- すべての要素でフォーカスインジケーターが見える
- カスタムフォーカススタイルがコントラスト要件を満たしている
:focus {
outline: 3px solid #005fcc;
outline-offset: 2px;
}
2.4.11 フォーカスを隠さない(レベル AA)- WCAG 2.2
- フォーカス中の要素が完全に隠れない
- 固定ヘッダーがフォーカスを隠さない
### Understandable (Principle 3)
```markdown
## 3.1 Readable
### 3.1.1 Language of Page (Level A)
- [ ] HTML lang attribute set
- [ ] Language correct for content
```html
<html lang="en">
3.1.2 部分的な言語の指定(レベル AA)
- 言語の変更がマークされている
<p>The French word <span lang="fr">bonjour</span> means hello.</p>
3.2 予測可能
3.2.1 フォーカス時(レベル A)
- フォーカスだけでコンテキストが変わらない
- フォーカス時に予期しないポップアップが表示されない
3.2.2 入力時(レベル A)
- フォームが自動送信されない
- コンテキストの変更前にユーザーに警告する
3.2.3 一貫したナビゲーション(レベル AA)
- ページ間でナビゲーションが一貫している
- 繰り返し使用するコンポーネントの順序が同じである
3.2.4 一貫した識別(レベル AA)
- 同じ機能には同じラベルを使用する
- アイコンを一貫して使用する
3.3 入力支援
3.3.1 エラーの識別(レベル A)
- エラーが明確に識別されている
- エラーメッセージが問題を説明している
- エラーがフィールドに関連付けられている
<input aria-describedby="email-error" aria-invalid="true" />
<span id="email-error" role="alert">Please enter valid email</span>
3.3.2 ラベルまたは説明(レベル A)
- すべての入力に表示されるラベルがある
- 必須フィールドが示されている
- 入力形式のヒントが示されている
3.3.3 エラーの修正案(レベル AA)
- エラーに修正案が含まれている
- 修正案が具体的である
3.3.4 エラーの防止(レベル AA)
- 法的または金銭に関するフォームで、入力を取り消せる
- 送信前にデータが確認される
- 送信前にユーザーが内容を確認できる
### Robust (Principle 4)
```markdown
## 4.1 Compatible
### 4.1.1 Parsing (Level A) - Obsolete in WCAG 2.2
- [ ] Valid HTML (good practice)
- [ ] No duplicate IDs
- [ ] Complete start/end tags
### 4.1.2 Name, Role, Value (Level A)
- [ ] Custom widgets have accessible names
- [ ] ARIA roles correct
- [ ] State changes announced
```html
<div role="checkbox"
aria-checked="false"
tabindex="0"
aria-labelledby="label">
</div>
<span id="label">Accept terms</span>
4.1.3 ステータスメッセージ(レベル AA)
- ステータスの更新が通知される
- ライブリージョンが正しく使用されている
<div role="status" aria-live="polite">3 items added to cart</div>
<div role="alert" aria-live="assertive">Error: Form submission failed</div>
## Automated Testing
```javascript
// axe-core integration
const axe = require('axe-core');
async function runAccessibilityAudit(page) {
await page.addScriptTag({ path: require.resolve('axe-core') });
const results = await page.evaluate(async () => {
return await axe.run(document, {
runOnly: {
type: 'tag',
values: ['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa']
}
});
});
return {
violations: results.violations,
passes: results.passes,
incomplete: results.incomplete
};
}
// Playwright test example
test('should have no accessibility violations', async ({ page }) => {
await page.goto('/');
const results = await runAccessibilityAudit(page);
expect(results.violations).toHaveLength(0);
});
# CLI tools
npx @axe-core/cli https://example.com
npx pa11y https://example.com
lighthouse https://example.com --only-categories=accessibility
改善パターン
修正:フォームラベルがない
<input type="email" placeholder="Email" />
<label for="email">Email address</label>
<input id="email" type="email" />
<input type="email" aria-label="Email address" />
<span id="email-label">Email</span>
<input type="email" aria-labelledby="email-label" />
修正:色のコントラストが不十分
/* Before: 2.5:1 contrast */
.text {
color: #767676;
}
/* After: 4.5:1 contrast */
.text {
color: #595959;
}
/* Or add background */
.text {
color: #767676;
background: #000;
}
修正:キーボードナビゲーション
// Make custom element keyboard accessible
class AccessibleDropdown extends HTMLElement {
connectedCallback() {
this.setAttribute("tabindex", "0");
this.setAttribute("role", "combobox");
this.setAttribute("aria-expanded", "false");
this.addEventListener("keydown", (e) => {
switch (e.key) {
case "Enter":
case " ":
this.toggle();
e.preventDefault();
break;
case "Escape":
this.close();
break;
case "ArrowDown":
this.focusNext();
e.preventDefault();
break;
case "ArrowUp":
this.focusPrevious();
e.preventDefault();
break;
}
});
}
}
ベストプラクティス
推奨事項
- 早期に着手する - 設計段階からアクセシビリティに取り組みます
- 実際のユーザーでテストする - 障害のあるユーザーから最も有益なフィードバックが得られます
- 自動化できることは自動化する - 問題の30~50%は検出可能です
- セマンティックHTMLを使用する - ARIAの必要性を減らせます
- パターンを文書化する - アクセシブルなコンポーネントライブラリを構築します
避けるべきこと
- 自動テストだけに頼らない - 手動テストも必要です
- 最初の解決策としてARIAを使わない - まずネイティブHTMLを使用します
- フォーカスのアウトラインを隠さない - キーボードを使うユーザーには必要です
- ズームを無効にしない - ユーザーが表示サイズを変更できる必要があります
- 色だけに頼らない - 複数の識別手段が必要です
コメント
Markdown 対応