accessibility
WCAG 2.1ガイドラインに従い、Webアクセシビリティの監査と改善を行います。「アクセシビリティの改善」「a11y監査」「WCAGコンプライアンス」「スクリーンリーダー対応」「キーボードナビゲーション」「アクセシブルにしてほしい」といった要求があった際に使用します。
description の原文を見る
Audit and improve web accessibility following WCAG 2.1 guidelines. Use when asked to "improve accessibility", "a11y audit", "WCAG compliance", "screen reader support", "keyboard navigation", or "make accessible".
SKILL.md 本文
アクセシビリティ (a11y)
WCAG 2.1 と Lighthouse アクセシビリティ監査に基づく包括的なアクセシビリティガイドライン。目標:障害者を含むすべての人がコンテンツを利用できるようにすること。
WCAG の 4 つの原則:POUR
| 原則 | 説明 |
|---|---|
| Perceivable (知覚可能) | 異なる感覚でコンテンツを知覚できる |
| Operable (操作可能) | すべてのユーザーがインターフェースを操作できる |
| Understandable (理解可能) | コンテンツとインターフェースが理解しやすい |
| Robust (堅牢) | 支援技術で動作する |
適合レベル
| レベル | 要件 | 目標 |
|---|---|---|
| A | 最小限のアクセシビリティ | 必須 |
| AA | 標準的な適合 | 推奨(多くの地域で法的要件) |
| AAA | 強化されたアクセシビリティ | あると良い |
知覚可能 (Perceivable)
テキストの代替表現 (1.1)
画像には代替テキストが必要:
<!-- ❌ 代替テキストがない -->
<img src="chart.png">
<!-- ✅ 説明的な代替テキスト -->
<img src="chart.png" alt="Q3 の売上が 40% 増加を示す棒グラフ">
<!-- ✅ 装飾的な画像(空の代替テキスト) -->
<img src="decorative-border.png" alt="" role="presentation">
<!-- ✅ 複雑な画像で長い説明付き -->
<figure>
<img src="infographic.png" alt="2024 年の市場トレンドインフォグラフィック"
aria-describedby="infographic-desc">
<figcaption id="infographic-desc">
<!-- 詳細な説明 -->
</figcaption>
</figure>
アイコンボタンはアクセシビリティ名が必要:
<!-- ❌ アクセシビリティ名がない -->
<button><svg><!-- メニューアイコン --></svg></button>
<!-- ✅ aria-label を使用 -->
<button aria-label="メニューを開く">
<svg aria-hidden="true"><!-- メニューアイコン --></svg>
</button>
<!-- ✅ 視覚的に隠されたテキストを使用 -->
<button>
<svg aria-hidden="true"><!-- メニューアイコン --></svg>
<span class="visually-hidden">メニューを開く</span>
</button>
視覚的に隠されたクラス:
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
色コントラスト (1.4.3, 1.4.6)
| テキストサイズ | AA 最小値 | AAA 強化値 |
|---|---|---|
| 通常テキスト (< 18px / < 14px 太字) | 4.5:1 | 7:1 |
| 大きいテキスト (≥ 18px / ≥ 14px 太字) | 3:1 | 4.5:1 |
| UI コンポーネント & グラフィック | 3:1 | 3:1 |
/* ❌ 低コントラスト (2.5:1) */
.low-contrast {
color: #999;
background: #fff;
}
/* ✅ 十分なコントラスト (7:1) */
.high-contrast {
color: #333;
background: #fff;
}
/* ✅ フォーカス状態もコントラストが必要 */
:focus-visible {
outline: 2px solid #005fcc;
outline-offset: 2px;
}
色だけに頼らない:
<!-- ❌ 色だけでエラーを示す -->
<input class="error-border">
<style>.error-border { border-color: red; }</style>
<!-- ✅ 色 + アイコン + テキスト -->
<div class="field-error">
<input aria-invalid="true" aria-describedby="email-error">
<span id="email-error" class="error-message">
<svg aria-hidden="true"><!-- エラーアイコン --></svg>
有効なメールアドレスを入力してください
</span>
</div>
メディアの代替コンテンツ (1.2)
<!-- キャプション付きビデオ -->
<video controls>
<source src="video.mp4" type="video/mp4">
<track kind="captions" src="captions.vtt" srclang="ja" label="日本語" default>
<track kind="descriptions" src="descriptions.vtt" srclang="ja" label="説明">
</video>
<!-- トランスクリプト付きオーディオ -->
<audio controls>
<source src="podcast.mp3" type="audio/mp3">
</audio>
<details>
<summary>トランスクリプト</summary>
<p>完全なトランスクリプトテキスト...</p>
</details>
操作可能 (Operable)
キーボードアクセス (2.1)
すべての機能がキーボードでアクセス可能である必要があります:
// ❌ クリックのみ対応
element.addEventListener('click', handleAction);
// ✅ クリックとキーボードの両方に対応
element.addEventListener('click', handleAction);
element.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
handleAction();
}
});
キーボードトラップなし:
// モーダルのフォーカス管理
function openModal(modal) {
const focusableElements = modal.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];
// モーダル内にフォーカスを制限
modal.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
if (e.shiftKey && document.activeElement === firstElement) {
e.preventDefault();
lastElement.focus();
} else if (!e.shiftKey && document.activeElement === lastElement) {
e.preventDefault();
firstElement.focus();
}
}
if (e.key === 'Escape') {
closeModal();
}
});
firstElement.focus();
}
フォーカス表示 (2.4.7)
/* ❌ フォーカスアウトラインを削除しない */
*:focus { outline: none; }
/* ✅ キーボード入力時のフォーカスに :focus-visible を使用 */
:focus {
outline: none;
}
:focus-visible {
outline: 2px solid #005fcc;
outline-offset: 2px;
}
/* ✅ または カスタムフォーカススタイル */
button:focus-visible {
box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.5);
}
スキップリンク (2.4.1)
<body>
<a href="#main-content" class="skip-link">メインコンテンツへスキップ</a>
<header><!-- ナビゲーション --></header>
<main id="main-content" tabindex="-1">
<!-- メインコンテンツ -->
</main>
</body>
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #000;
color: #fff;
padding: 8px 16px;
z-index: 100;
}
.skip-link:focus {
top: 0;
}
タイミング (2.2)
// ユーザーが時間制限を延長できるようにする
function showSessionWarning() {
const modal = createModal({
title: 'セッション期限切れ間近',
content: 'セッションは 2 分後に期限切れになります。',
actions: [
{ label: 'セッションを延長', action: extendSession },
{ label: 'ログアウト', action: logout }
],
timeout: 120000 // 応答時間は 2 分
});
}
モーション (2.3)
/* 削減されたモーションの優先設定に対応 */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
理解可能 (Understandable)
ページの言語 (3.1.1)
<!-- ❌ 言語が指定されていない -->
<html>
<!-- ✅ 言語が指定されている -->
<html lang="ja">
<!-- ✅ ページ内での言語変更 -->
<p>英語で hello は <span lang="en">hello</span> です。</p>
一貫したナビゲーション (3.2.3)
<!-- ナビゲーションはページ全体で一貫している必要があります -->
<nav aria-label="メイン">
<ul>
<li><a href="/" aria-current="page">ホーム</a></li>
<li><a href="/products">製品</a></li>
<li><a href="/about">について</a></li>
</ul>
</nav>
フォームラベル (3.3.2)
<!-- ❌ ラベルの関連付けがない -->
<input type="email" placeholder="メールアドレス">
<!-- ✅ 明示的なラベル -->
<label for="email">メールアドレス</label>
<input type="email" id="email" name="email"
autocomplete="email" required>
<!-- ✅ 暗黙的なラベル -->
<label>
メールアドレス
<input type="email" name="email" autocomplete="email" required>
</label>
<!-- ✅ 指示付き -->
<label for="password">パスワード</label>
<input type="password" id="password"
aria-describedby="password-requirements">
<p id="password-requirements">
8 文字以上で、1 つ以上の数字を含む必要があります。
</p>
エラーハンドリング (3.3.1, 3.3.3)
<!-- スクリーンリーダーにエラーを通知 -->
<form novalidate>
<div class="field" aria-live="polite">
<label for="email">メールアドレス</label>
<input type="email" id="email"
aria-invalid="true"
aria-describedby="email-error">
<p id="email-error" class="error" role="alert">
有効なメールアドレスを入力してください(例:name@example.com)
</p>
</div>
</form>
// 送信時に最初のエラーにフォーカス
form.addEventListener('submit', (e) => {
const firstError = form.querySelector('[aria-invalid="true"]');
if (firstError) {
e.preventDefault();
firstError.focus();
// エラーサマリーを通知
const errorSummary = document.getElementById('error-summary');
errorSummary.textContent = `${errors.length} 個のエラーが見つかりました。修正して再度試してください。`;
errorSummary.focus();
}
});
堅牢 (Robust)
有効な HTML (4.1.1)
<!-- ❌ 重複する ID -->
<div id="content">...</div>
<div id="content">...</div>
<!-- ❌ 無効なネスト -->
<a href="/"><button>クリック</button></a>
<!-- ✅ 一意の ID -->
<div id="main-content">...</div>
<div id="sidebar-content">...</div>
<!-- ✅ 適切なネスト -->
<a href="/" class="button-link">クリック</a>
ARIA の使用 (4.1.2)
ネイティブ要素を優先:
<!-- ❌ div に ARIA ロール -->
<div role="button" tabindex="0">クリック</div>
<!-- ✅ ネイティブボタン -->
<button>クリック</button>
<!-- ❌ ARIA チェックボックス -->
<div role="checkbox" aria-checked="false">オプション</div>
<!-- ✅ ネイティブチェックボックス -->
<label><input type="checkbox"> オプション</label>
ARIA が必要な場合:
<!-- カスタムタブコンポーネント -->
<div role="tablist" aria-label="製品情報">
<button role="tab" id="tab-1" aria-selected="true"
aria-controls="panel-1">説明</button>
<button role="tab" id="tab-2" aria-selected="false"
aria-controls="panel-2" tabindex="-1">レビュー</button>
</div>
<div role="tabpanel" id="panel-1" aria-labelledby="tab-1">
<!-- パネルコンテンツ -->
</div>
<div role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>
<!-- パネルコンテンツ -->
</div>
ライブリージョン (4.1.3)
<!-- ステータス更新 -->
<div aria-live="polite" aria-atomic="true" class="status">
<!-- コンテンツの更新がスクリーンリーダーに通知される -->
</div>
<!-- 緊急アラート -->
<div role="alert" aria-live="assertive">
<!-- 現在の読み上げを中断 -->
</div>
// 動的コンテンツの変更を通知
function showNotification(message, type = 'polite') {
const container = document.getElementById(`${type}-announcer`);
container.textContent = ''; // まずクリア
requestAnimationFrame(() => {
container.textContent = message;
});
}
テストチェックリスト
自動テスト
# Lighthouse アクセシビリティ監査
npx lighthouse https://example.com --only-categories=accessibility
# axe-core
npm install @axe-core/cli -g
axe https://example.com
手動テスト
- キーボードナビゲーション: ページ全体をTab キーで移動、Enter/Space で実行
- スクリーンリーダー: VoiceOver (Mac)、NVDA (Windows)、TalkBack (Android) でテスト
- ズーム: 200% ズームでコンテンツが利用可能
- 高コントラスト: Windows ハイコントラストモードでテスト
- 削減されたモーション:
prefers-reduced-motion: reduceでテスト - フォーカス順序: 論理的で視覚的順序に従っている
スクリーンリーダーコマンド
| 操作 | VoiceOver (Mac) | NVDA (Windows) |
|---|---|---|
| 開始/停止 | ⌘ + F5 | Ctrl + Alt + N |
| 次の項目 | VO + → | ↓ |
| 前の項目 | VO + ← | ↑ |
| 実行 | VO + Space | Enter |
| 見出しリスト | VO + U、矢印キー | H / Shift + H |
| リンクリスト | VO + U | K / Shift + K |
影響別の一般的な問題
重大(すぐに修正)
- フォームラベルがない
- 画像の代替テキストがない
- 色コントラストが不十分
- キーボードトラップ
- フォーカス表示がない
深刻(リリース前に修正)
- ページ言語の指定がない
- 見出し構造がない
- 説明的でないリンクテキスト
- 自動再生メディア
- スキップリンクがない
中程度(すぐに修正)
- アイコンの ARIA ラベルがない
- ナビゲーションの一貫性がない
- エラー識別がない
- タイミング制御がない
- ランドマークリージョンがない
参考資料
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- davila7
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/davila7/claude-code-templates / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。