wcag-design について
WCAG-Designは、アクセシブルなインターフェースを作るフロントエンドチーム向けのデザインスキルです。WCAG 2.2 AAの原則と達成基準を、知覚・操作・理解・堅牢性の観点から解説します。
主な機能
- 01WCAG 2.2 AAのガイダンス
- 02POURの4原則
- 03達成基準のリファレンス
- 04コンテンツと操作要素のアクセシビリティ指針
活用シーン
- 01WCAG基準に沿った画面の確認
- 02キーボードで操作できるナビゲーションの設計
- 03コントラスト・代替テキスト・リフローの確認
- 04フォームラベルとエラー処理の改善
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ alexsnchz/ skills --skill wcag-designインストール後、Claude Code で/wcag-designを入力して読み込まれたか確認します。
同梱ファイルREADME.md
詳細
WCAG-Design スキル
このスキルでは、WCAG 2.2 AA 規格に準拠した、アクセシブルで視覚的にも際立つフロントエンドインターフェースの作成を支援します。アクセシビリティとデザイン品質は相反するものではありません。最もアクセシブルなインターフェースは、美しくデザインされています。
パート 1 — WCAG の基本
WCAG とは?
Web Content Accessibility Guidelines(WCAG) は、W3C の Web Accessibility Initiative(WAI)が公開している、ウェブアクセシビリティの国際標準です。WCAG は、視覚障害、ロービジョン、聴覚障害、難聴、運動機能の制限、光過敏症、発話障害、認知障害や学習障害のある人がウェブコンテンツを利用できるようにする方法を定めています。
バージョンの歴史
| バージョン | 年 | 注記 |
|---|---|---|
| WCAG 1.0 | 1999 | W3C 初のアクセシビリティ勧告 |
| WCAG 2.0 | 2008 | テスト可能な達成基準を導入した大幅な再構成 |
| WCAG 2.1 | 2018 | モバイル、ロービジョン、認知機能に関する基準を 17 項目追加 |
| WCAG 2.2 | 2023 | 新基準を 9 項目追加し、4.1.1 Parsing を削除。現行標準 |
| WCAG 3.0 | ~2028 | ドラフト。平易な言葉と成果重視のモデル |
後方互換性:WCAG 2.2 に準拠したコンテンツは、2.1 および 2.0 にも準拠します。
パート 2 — 4 つの POUR 原則
WCAG のすべての達成基準は、次の 4 つの原則のいずれかに対応しています。
1. 知覚可能(P)
すべての情報と UI コンポーネントは、ユーザーが知覚できる方法で提示する必要があります。
- 非テキストコンテンツにテキストによる代替を用意する
- メディアにキャプションと音声解説を付ける
- コンテンツの提示方法を変更できるようにする
- 十分な色のコントラストと読みやすさを確保する
2. 操作可能(O)
すべての UI コンポーネントとナビゲーションは、操作可能である必要があります。
- キーボードで完全にアクセスできる
- キーボードトラップがない
- 操作に十分な時間を確保する
- 発作を引き起こすコンテンツがない
- 複数の入力方法に対応する(キーボード、タッチ、音声)
- フォーカスを適切に管理する
3. 理解可能(U)
ユーザーがコンテンツとインターフェースの動作を理解できる必要があります。
- 読みやすく、理解しやすいテキスト
- 予測可能で一貫した動作
- 入力支援とエラーからの回復
- 明確な言葉と定義
4. 堅牢(R)
コンテンツは、特に支援技術を含む現在および将来のテクノロジーで確実に動作する必要があります。
- 有効で適切に構成されたマークアップ
- ブラウザーと支援技術との互換性
- 適切なセマンティック構造
パート 3 — 適合レベル
| レベル | 基準数 | 説明 |
|---|---|---|
| A | 32 | 最低限 — 基本的なアクセシビリティ、基礎的な適合 |
| AA | +24(合計 56) | 推奨 — ほとんどの法的要件に対応し、一般的な障壁に対処 |
| AAA | +31(合計 87) | 強化 — 最高レベル。ただし常に必須とは限らない |
目標:WCAG 2.2 AA — ADA、EN 301 549、Section 508、Accessibility for Ontarians with Disabilities Act など、ほとんどのアクセシビリティ関連法で求められるレベルです。
パート 4 — WCAG 2.2 達成基準の完全リファレンス
原則 1:知覚可能
ガイドライン 1.1 — テキストによる代替
| 基準 | レベル | ルール |
|---|---|---|
| 1.1.1 非テキストコンテンツ | A | すべての非テキストコンテンツ(画像、アイコン、グラフ、ボタン)にテキストによる代替がある |
ガイドライン 1.2 — 時間依存メディア
| 基準 | レベル | ルール |
|---|---|---|
| 1.2.1 音声のみおよび映像のみ(収録済み) | A | 文字起こしまたは音声解説を提供する |
| 1.2.2 キャプション(収録済み) | A | マルチメディア内の収録済み音声すべてにキャプションを付ける |
| 1.2.3 音声解説またはメディアの代替(収録済み) | A | 音声解説または完全なテキストによる代替を提供する |
| 1.2.4 キャプション(ライブ) | AA | ライブマルチメディアすべてにキャプションを付ける |
| 1.2.5 音声解説(収録済み) | AA | 収録済み動画すべてに音声解説を付ける |
| 1.2.6 手話(収録済み) | AAA | 収録済み音声に手話通訳を付ける |
| 1.2.7 拡張音声解説(収録済み) | AAA | 一時停止だけでは不十分な場合、拡張音声解説を提供する |
| 1.2.8 メディアの代替(収録済み) | AAA | 収録済みメディアすべてに完全なテキストによる代替を提供する |
| 1.2.9 音声のみ(ライブ) | AAA | ライブ音声のみのコンテンツすべてに代替を提供する |
ガイドライン 1.3 — 適応可能
| 基準 | レベル | ルール |
|---|---|---|
| 1.3.1 情報と関係性 | A | 表示を通じて伝えられる構造と関係性を、プログラムによって判別できる |
| 1.3.2 意味のある順序 | A | 読み取り順序とナビゲーション順序が論理的である |
| 1.3.3 感覚的な特徴 | A | 指示が色、サイズ、形状、視覚的な位置、または音のみに依存しない |
| 1.3.4 表示方向 | AA | コンテンツが縦向きまたは横向きのどちらかに限定されない |
| 1.3.5 入力の目的の特定 | AA | 入力フィールドの目的をプログラムによって特定できる(オートコンプリート) |
| 1.3.6 目的の特定 | AAA | ボタン、リンク、コントロールの目的をプログラムによって判別できる |
ガイドライン 1.4 — 判別可能
| 基準 | レベル | ルール |
|---|---|---|
| 1.4.1 色の使用 | A | 情報を伝える視覚的な手段が色のみではない |
| 1.4.2 音声の制御 | A | 自動再生される音声を一時停止、停止、または音量調節できる |
| 1.4.3 コントラスト(最低限) | AA | 通常のテキストは4.5:1、大きなテキストは3:1 |
| 1.4.4 テキストのサイズ変更 | AA | コンテンツを失うことなく、テキストを200%まで拡大できる |
| 1.4.5 テキスト画像 | AA | 可能な場合は、テキスト画像の代わりに実際のテキストを使用する |
| 1.4.6 コントラスト(強化) | AAA | 通常のテキストは7:1、大きなテキストは4.5:1 |
| 1.4.7 背景音を小さく、または使用しない | AAA | 音声のみのコンテンツが背景音の上でも明瞭に聞こえる |
| 1.4.8 視覚的な表示 | AAA | テキストの幅が制限され、行間を調整でき、両端揃えを使用しない |
| 1.4.9 テキスト画像(例外なし) | AAA | ロゴを除き、テキスト画像を使用しない |
| 1.4.10 リフロー | AA | 幅320pxで横スクロールせずにコンテンツを表示できる |
| 1.4.11 非テキストのコントラスト | AA | UI コンポーネントとグラフィック要素のコントラスト比が3:1である |
| 1.4.12 テキストの間隔 | AA | 行の高さを1.5倍以上、文字間隔を0.12em以上、単語間隔を0.16em以上にしてもコンテンツが失われない |
| 1.4.13 ホバーまたはフォーカス時のコンテンツ | AA | ホバーまたはフォーカス可能なコンテンツを閉じることができ、ホバー可能で、表示が維持される |
原則 2:操作可能
ガイドライン 2.1 — キーボードで操作可能
| 基準 | レベル | ルール |
|---|---|---|
| 2.1.1 キーボード | A | すべての機能をキーボードで操作できる |
| 2.1.2 キーボードトラップなし | A | ユーザーがキーボードを使って、どのコンポーネントからも移動できる |
| 2.1.3 キーボード(例外なし) | AAA | 例外なく、すべての機能をキーボードで操作できる |
| 2.1.4 文字キーのショートカット | A | 1文字のショートカットを無効化または再割り当てできる |
ガイドライン 2.2 — 十分な時間
| 達成基準 | レベル | ルール |
|---|---|---|
| 2.2.1 時間調整可能 | A | 時間制限を無効化、調整、または延長(デフォルトの10倍以上)できます |
| 2.2.2 一時停止、停止、非表示 | A | 自動で移動、点滅、スクロールするコンテンツを一時停止、停止、または非表示にできます |
| 2.2.3 時間制限なし | AAA | リアルタイムイベントを除き、時間制限はありません |
| 2.2.4 中断 | AAA | すべての中断を延期または抑制できます |
| 2.2.5 再認証 | AAA | タイムアウト後に再認証してもデータは失われません |
| 2.2.6 タイムアウト | AAA | セッションの非アクティブ状態によるタイムアウトをユーザーに警告します |
ガイドライン 2.3 — 発作と身体的反応
| 達成基準 | レベル | ルール |
|---|---|---|
| 2.3.1 3回以下の点滅、またはしきい値以下 | A | 1秒間に3回を超える点滅コンテンツはありません(またはしきい値以下です) |
| 2.3.2 3回の点滅 | AAA | すべてのコンテンツの点滅は1秒間に3回以下に制限されています |
| 2.3.3 インタラクションによるアニメーション | AAA | インタラクションによって開始されるモーションアニメーションを無効にできます |
ガイドライン 2.4 — ナビゲーション可能
| 達成基準 | レベル | ルール |
|---|---|---|
| 2.4.1 ブロックのスキップ | A | 繰り返し表示されるブロックをスキップする仕組み(ナビゲーションをスキップするリンク)があります |
| 2.4.2 ページタイトル | A | ウェブページには内容を説明するタイトルがあります |
| 2.4.3 フォーカス順序 | A | フォーカス順序は論理的で意味があります |
| 2.4.4 リンクの目的(文脈内) | A | リンクのテキストまたは文脈からリンクの目的が明確です |
| 2.4.5 複数の方法 | AA | ページを見つける方法が複数あります(検索、サイトマップ、ナビゲーション) |
| 2.4.6 見出しとラベル | AA | 見出しとラベルがトピックまたは目的を説明しています |
| 2.4.7 フォーカスの可視化 | AA | キーボードフォーカスインジケーターが表示されます |
| 2.4.8 位置 | AAA | ユーザーが一連のページ内での現在位置を把握できます |
| 2.4.9 リンクの目的(リンクのみ) | AAA | リンクのテキストだけでリンクの目的が明確です |
| 2.4.10 セクション見出し | AAA | セクション見出しがコンテンツを整理しています |
| 2.4.11 フォーカスが隠れないこと(最低限) ⭐ 新規 2.2 | AA | フォーカスされた要素が、固定表示コンテンツによって完全に隠れません |
| 2.4.12 フォーカスが隠れないこと(強化) ⭐ 新規 2.2 | AAA | フォーカスされた要素が完全に表示されます |
| 2.4.13 フォーカスの外観 ⭐ 新規 2.2 | AAA | フォーカスインジケーターは、2px以上のアウトラインと3:1以上のコントラスト変化を備えています |
ガイドライン 2.5 — 入力モダリティ
| 達成基準 | レベル | ルール |
|---|---|---|
| 2.5.1 ポインタージェスチャ | A | 経路に基づくジェスチャには、シングルポインターによる代替操作があります |
| 2.5.2 ポインターのキャンセル | A | ポインター操作は「押したとき」ではなく「離したとき」に実行されます |
| 2.5.3 名前に含まれるラベル | A | アクセシブルな名前に、画面に表示されているラベルのテキストが含まれています |
| 2.5.4 モーションによる作動 | A | モーションによって起動する機能にはUIによる代替操作があり、無効にできます |
| 2.5.5 ターゲットサイズ(強化) | AAA | タッチターゲットは44×44 CSSピクセル以上です |
| 2.5.6 複数の入力手段 | AAA | 入力モダリティに制限はありません |
| 2.5.7 ドラッグ操作 ⭐ 新規 2.2 | AA | ドラッグのみで操作できる機能には、シングルポインターによる代替操作があります |
| 2.5.8 ターゲットサイズ(最低限) ⭐ 新規 2.2 | AA | タッチターゲットは24×24 CSSピクセル以上、または十分な間隔があります |
原則 3:理解可能
ガイドライン 3.1 — 読みやすさ
| 達成基準 | レベル | ルール |
|---|---|---|
| 3.1.1 ページの言語 | A | デフォルトの自然言語がプログラムで識別されています(lang属性) |
| 3.1.2 部分ごとの言語 | AA | コンテンツ内の言語の変化が示されています |
| 3.1.3 珍しい単語 | AAA | 専門用語、慣用表現、技術用語の定義があります |
| 3.1.4 略語 | AAA | 略語は初出時に正式名称が示されています |
| 3.1.5 読解レベル | AAA | 前期中等教育レベルのテキスト、または簡易版が利用できます |
| 3.1.6 発音 | AAA | 発音が曖昧な単語には発音が示されています |
ガイドライン 3.2 — 予測可能
| 基準 | レベル | ルール |
|---|---|---|
| 3.2.1 フォーカス時 | A | コンポーネントがフォーカスを受け取っても、コンテキストを変更しない |
| 3.2.2 入力時 | A | 設定を変更しても、フォームを自動的に送信しない |
| 3.2.3 一貫したナビゲーション | AA | ページ間でナビゲーションの仕組みを同じ相対順序で配置する |
| 3.2.4 一貫した識別 | AA | 同じ機能を持つコンポーネントは一貫して識別する |
| 3.2.5 要求時の変更 | AAA | コンテキストを変更するのはユーザーが要求した場合のみ |
| 3.2.6 一貫したヘルプ ⭐ NEW 2.2 | A | ページ間でヘルプの仕組みを同じ場所に配置する |
ガイドライン 3.3 — 入力支援
| 基準 | レベル | ルール |
|---|---|---|
| 3.3.1 エラーの識別 | A | エラーを識別し、テキストで説明する |
| 3.3.2 ラベルまたは説明 | A | すべての入力にラベルまたは説明を提供する |
| 3.3.3 エラーの提案 | AA | 入力エラーに対して、既知の場合は修正案を提示する |
| 3.3.4 エラー防止(法的、金銭的、データ) | AA | 重要な送信は取り消し、確認、または確定できるようにする |
| 3.3.5 ヘルプ | AAA | コンテキストに応じたヘルプを利用できる |
| 3.3.6 エラー防止(すべて) | AAA | すべての入力を取り消し、確認、または確定できる |
| 3.3.7 冗長な入力 ⭐ NEW 2.2 | A | 同じセッション内で、以前に入力した情報を再度求めない |
| 3.3.8 アクセシブルな認証(最小) ⭐ NEW 2.2 | AA | 認知機能テストや記憶を必要としない認証 |
| 3.3.9 アクセシブルな認証(強化) ⭐ NEW 2.2 | AAA | 認知機能テストに代わる強化された選択肢 |
原則 4:堅牢
ガイドライン 4.1 — 互換性
| 基準 | レベル | ルール |
|---|---|---|
| WCAG 2.2 で削除 — HTML5 のエラー修正により不要 | ||
| 4.1.2 名前、役割、値 | A | すべてのコンポーネントにアクセシブルな名前、役割、状態/値がある |
| 4.1.3 ステータスメッセージ | AA | フォーカスを変更せずに、スクリーンリーダーへステータスメッセージを通知する |
パート 5 — 実装リファレンス
5.1 色のコントラストに関するルール
| コンテキスト | AA 最低基準 | AAA 強化基準 |
|---|---|---|
| 通常のテキスト(<18px または <14px の太字) | 4.5:1 | 7:1 |
| 大きなテキスト(≥18px または ≥14px の太字) | 3:1 | 4.5:1 |
| UI コンポーネントとグラフィック | 3:1 | 3:1 |
| プレースホルダーテキスト | 4.5:1 | — |
| 無効な要素 | 対象外 | 対象外 |
| 装飾要素 | 対象外 | 対象外 |
ダークモードに関する注意: ダークテーマでもコントラスト比を満たす必要があります。純粋な黒 #000000
(ハレーションや眼精疲労の原因になります)は避け、#0f0f0f や #121212 のような柔らかい黒を使用してください。
暗い背景に高彩度の色を使うと視覚的にちらつくことがあるため、彩度を下げてください。
ツール: WebAIM Contrast Checker、Colour Contrast Analyser、axe DevTools、Chrome DevTools。
5.2 セマンティック HTML — まずネイティブ要素を使用する
常に ARIA よりセマンティック HTML を優先してください。ARIA は補足であり、代替ではありません。
<header>…</header>
<nav aria-label="Main navigation">…</nav>
<main>
<article>…</article>
<aside>…</aside>
</main>
<footer>…</footer>
<div class="header">…</div>
<div class="nav">…</div>
セマンティック要素 → ランドマークの対応:
| 要素 | ARIA ランドマークの役割 |
|---|---|
<header> | banner |
<nav> | navigation |
<main> | main |
<aside> | complementary |
<footer> | contentinfo |
<section aria-label="..."> | region |
<form> | form |
見出し階層のルール: レベルを飛ばしてはいけません。<h1> → <h2> → <h3>(h1 → h3 ではありません)。
複数の <h1> 要素を使用してもかまいませんが、最初の要素はページまたはセクションのタイトルにしてください。
5.3 WAI-ARIA クイックリファレンス
セマンティック HTML だけでは不十分な場合に限り、ARIA を使用してください。ARIA の第一ルール: 意味が組み込まれたネイティブ HTML 要素または属性を使える場合は、ARIA を使用しないでください。
ランドマークロール
<div role="banner">…</div>
<div role="navigation">…</div>
<div role="main">…</div>
<div role="complementary">…</div>
<div role="contentinfo">…</div>
<div role="search">…</div>
<div role="region" aria-label="…">…</div>
ウィジェットロール(インタラクティブコンポーネント)
role="button"
role="checkbox"
role="radio"
role="combobox"
role="listbox"
role="option"
role="menu"
role="menuitem"
role="tab"
role="tablist"
role="tabpanel"
role="dialog"
role="alertdialog"
role="slider"
role="progressbar"
role="tooltip"
role="tree"
role="treeitem"
role="grid"
role="gridcell"
ライブリージョンのロール(動的コンテンツ)
role="alert"
role="status"
role="log"
role="timer"
aria-live="polite"
aria-live="assertive"
aria-live="off"
aria-atomic="true"
aria-relevant="additions text"
必須の ARIA プロパティ
aria-label="Close dialog"
aria-labelledby="heading-id"
aria-describedby="description-id help-text-id"
aria-expanded="true|false"
aria-selected="true|false"
aria-checked="true|false|mixed"
aria-pressed="true|false|mixed"
aria-disabled="true"
aria-hidden="true"
aria-invalid="true|false|grammar|spelling"
aria-busy="true|false"
aria-controls="panel-id"
aria-owns="list-id"
aria-haspopup="true|menu|listbox|tree|grid|dialog"
aria-autocomplete="none|inline|list|both"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="50"
aria-valuetext="50 percent"
aria-current="page|step|location|date|time|true|false"
5.4 キーボードナビゲーションの実装
すべてのインタラクティブコンポーネントは、キーボードで完全に操作できる必要があります。
フォーカス管理のルール
/* NEVER do this without a custom replacement */
*:focus { outline: none; }
/* ✅ Custom focus indicator — meets WCAG 2.4.7 and 2.4.13 */
:focus-visible {
outline: 2px solid #005fcc;
outline-offset: 2px;
border-radius: 2px;
}
/* Different styles for mouse vs keyboard */
:focus:not(:focus-visible) { outline: none; }
:focus-visible { outline: 2px solid #005fcc; outline-offset: 2px; }
タブ順序
<div role="button" tabindex="0">Custom Button</div>
<button tabindex="3">Bad</button>
<div tabindex="-1" id="modal-content">…</div>
ナビゲーションをスキップするリンク
<a href="#main-content" class="skip-link">Skip to main content</a>
<style>
.skip-link {
position: absolute;
top: -100%;
left: 0;
padding: 0.5rem 1rem;
background: #000;
color: #fff;
z-index: 9999;
transition: top 0.1s;
}
.skip-link:focus { top: 0; }
</style>
<main id="main-content">…</main>
コンポーネント別のキーボード操作パターン
| コンポーネント | キー | 操作 |
|---|---|---|
| すべて | Tab | フォーカスを次に移動 |
| すべて | Shift+Tab | フォーカスを前に移動 |
| ボタン | Enter / Space | アクティブ化 |
| リンク | Enter | リンク先に移動 |
| チェックボックス | Space | 切り替え |
| ラジオグループ | 矢印キー | 選択肢を選択 |
| セレクト/ドロップダウン | 矢印キー | 移動、Enter で選択 |
| ダイアログ | Escape | 閉じる |
| ダイアログ | Tab | ダイアログ内のみでフォーカスを循環 |
| メニュー | 矢印キー | 項目間を移動 |
| メニュー | Escape | 閉じる |
| メニュー | Enter / Space | 項目をアクティブ化 |
| スライダー | 矢印キー | 増加/減少 |
| スライダー | Home / End | 最小値/最大値 |
| タブ | 矢印キー | タブを切り替え |
| ツリー | 矢印キー | 展開/折りたたみ/移動 |
モーダルのフォーカストラップ
// Trap focus within modal while open
function trapFocus(modal) {
const focusable = modal.querySelectorAll(
'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex="-1"])'
);
const firstEl = focusable[0];
const lastEl = focusable[focusable.length - 1];
modal.addEventListener('keydown', (e) => {
if (e.key !== 'Tab') return;
if (e.shiftKey) {
if (document.activeElement === firstEl) {
e.preventDefault(); lastEl.focus();
}
} else {
if (document.activeElement === lastEl) {
e.preventDefault(); firstEl.focus();
}
}
});
}
5.5 アクセシブルなコンポーネントのパターン
モーダル/ダイアログ
<dialog
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
aria-describedby="modal-desc"
id="my-modal"
>
<h2 id="modal-title">Confirm Action</h2>
<p id="modal-desc">Are you sure you want to delete this item?</p>
<button type="button" autofocus>Cancel</button>
<button type="button">Delete</button>
</dialog>
// HTML5 <dialog> — built-in focus management + Escape handling
const modal = document.getElementById('my-modal');
const trigger = document.getElementById('open-btn');
trigger.addEventListener('click', () => modal.showModal());
modal.addEventListener('close', () => trigger.focus()); // Restore focus
アクセシブルなボタン(カスタム)
<button type="button" aria-pressed="false" id="dark-toggle">
<svg aria-hidden="true" focusable="false">…</svg>
Dark Mode
</button>
<button type="button" aria-label="Close dialog">
<svg aria-hidden="true" focusable="false">…</svg>
</button>
アコーディオン
<div class="accordion">
<h3>
<button
type="button"
aria-expanded="false"
aria-controls="panel-1"
id="btn-1"
>Section Title</button>
</h3>
<div id="panel-1" role="region" aria-labelledby="btn-1" hidden>
Panel content here
</div>
</div>
タブ
<div role="tablist" aria-label="Settings sections">
<button role="tab" aria-selected="true" aria-controls="panel-a" id="tab-a" tabindex="0">General</button>
<button role="tab" aria-selected="false" aria-controls="panel-b" id="tab-b" tabindex="-1">Privacy</button>
</div>
<div role="tabpanel" id="panel-a" aria-labelledby="tab-a">…</div>
<div role="tabpanel" id="panel-b" aria-labelledby="tab-b" hidden>…</div>
コンボボックス/オートコンプリート
<label for="city-input">City</label>
<input
type="text"
id="city-input"
role="combobox"
aria-expanded="false"
aria-haspopup="listbox"
aria-autocomplete="list"
aria-controls="city-list"
/>
<ul id="city-list" role="listbox" aria-label="Cities">
<li role="option" id="opt-1">New York</li>
<li role="option" id="opt-2">Los Angeles</li>
</ul>
アラート/ステータスメッセージ
<div role="status" aria-live="polite" aria-atomic="true">
Form saved successfully.
</div>
<div role="alert" aria-live="assertive" aria-atomic="true">
Error: Please enter a valid email address.
</div>
5.6 フォーム — アクセシブルなパターン
<div class="field">
<label for="email">
Email address
<span aria-hidden="true" class="required">*</span>
<span class="sr-only">(required)</span>
</label>
<input
type="email"
id="email"
name="email"
autocomplete="email"
aria-required="true"
aria-describedby="email-hint email-error"
aria-invalid="false"
/>
<p id="email-hint" class="hint">We'll never share your email.</p>
<p id="email-error" class="error" role="alert" hidden>
Please enter a valid email address.
</p>
</div>
<fieldset>
<legend>Notification preferences</legend>
<label><input type="radio" name="notif" value="email"> Email</label>
<label><input type="radio" name="notif" value="sms"> SMS</label>
<label><input type="radio" name="notif" value="none"> None</label>
</fieldset>
フォームの検証ルール:
- すべてのキー入力ごとではなく、
blurまたはsubmitのタイミングで検証します - 無効なフィールドには
aria-invalid="true"を設定します aria-describedbyを使ってエラーメッセージをフィールドに関連付けます- 動的に挿入するエラーメッセージには
role="alert"を使用します - プレースホルダーテキストだけをラベルとして使用しないでください
- よく使われるフィールドには autocomplete 属性を設定します
5.7 画像と代替テキスト
<img src="chart.png" alt="Sales by region 2024: North 35%, South 28%, East 22%, West 15%">
<img src="divider.png" alt="">
<button aria-label="Search">
<img src="magnifier.svg" alt="">
</button>
<figure>
<img src="architecture.png" alt="System architecture diagram" aria-describedby="arch-desc">
<figcaption id="arch-desc">
Three-tier architecture: client tier connects to API gateway,
which routes to microservices cluster, backed by PostgreSQL and Redis.
</figcaption>
</figure>
<div class="hero-bg" role="img" aria-label="Abstract blue wave">…</div>
代替テキストのガイドライン:
- 簡潔にします(通常は 125 文字以下。複雑な内容の場合は最大 250 文字)
- 「Image of」や「Picture of」で始めないでください
- 見た目だけでなく、目的と内容を説明します
- グラフの場合:重要なデータポイントを含めます
- ロゴの場合:会社名のみを使用します
5.8 タイポグラフィのアクセシビリティ
/* ✅ Accessible base typography */
html {
font-size: 100%; /* Don't fix to px — respects user browser setting */
}
body {
font-size: 1rem; /* = 16px by default */
line-height: 1.5; /* Readable line spacing */
max-width: 75ch; /* Limit line length for readability */
font-family: /* Choose a readable, designed typeface */;
}
/* ✅ Allow text spacing override (WCAG 1.4.12) */
* {
line-height: inherit !important; /* only in text-spacing tests */
letter-spacing: inherit !important;
word-spacing: inherit !important;
}
/* ✅ Respect zoom — use relative units */
h1 { font-size: clamp(1.5rem, 4vw, 2.5rem); }
p { font-size: clamp(1rem, 1.2vw, 1.125rem); }
| ガイドライン | 最小値 | 推奨値 |
|---|---|---|
| 本文の文字サイズ | 14px (0.875rem) | 16px (1rem) |
| 行の高さ | 1.4 | 1.5–1.6 |
| 最大行長 | — | 65–75 文字 |
| 文字間隔 | — | 0~+0.05em |
| 段落間隔 | — | フォントサイズの 1.5 倍 |
アクセシビリティを考慮したフォント選択:
- 文字の形を明確に区別できる書体を選びます(b/d/p/q の違いなど)
- 本文に装飾的なフォントを使用しないでください
- 小さいサイズでは細いウェイト(300 未満)を避けます
- 読みやすさを確保するために、十分なエックスハイトを確保します
5.9 動きとアニメーション
/* ✅ Respect prefers-reduced-motion — implement always */
@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;
}
}
/* ✅ Progressive enhancement pattern */
.card { /* base — no motion */ }
@media (prefers-reduced-motion: no-preference) {
.card {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0,0,0,0.12);
}
}
動きに関するルール:
- 動きを伴う動画を自動再生しないでください —
prefers-reduced-motionを使用します - 点滅するコンテンツは 1 秒あたり最大 3 回までにします(WCAG 2.3.1)
- パララックスやページ全体のスクロールジャックには、
prefers-reduced-motion: reduceに対応する代替手段を用意します - ローディングスピナーは使用できますが、代替手段のないページ全体のアニメーション遷移は使用しないでください
5.10 レスポンシブ対応とモバイルのアクセシビリティ
/* ✅ WCAG 1.4.10 Reflow — no horizontal scroll at 320px */
@media (max-width: 320px) {
.container { width: 100%; padding: 0 1rem; }
table { display: block; overflow-x: auto; }
}
/* ✅ WCAG 2.5.8 Minimum target size — 24×24px with spacing */
button, a, [role="button"] {
min-height: 44px; /* Meet WCAG 2.5.5 AAA for comfort */
min-width: 44px;
padding: 0.5rem 1rem;
}
/* ✅ Ensure focus remains visible at all sizes */
:focus-visible {
outline: 2px solid currentColor;
outline-offset: 3px;
}
モバイル固有の考慮事項:
- 適切な
type属性を使用します:type="email"、type="tel"、type="number" - ズームを無効にしないでください:
<meta name="viewport" content="width=device-width, initial-scale=1">—user-scalable=noは絶対に追加しないでください - VoiceOver(iOS)と TalkBack(Android)でテストします
- ホバーのみのインタラクションは避けます(タッチデバイスではホバーできません)
- 数値、10 進数、電話番号、メールアドレス、URL、検索の各入力には
inputmode属性を設定します
5.11 テーブル
<table>
<caption>Q4 2024 Sales by Region</caption>
<thead>
<tr>
<th scope="col">Region</th>
<th scope="col">Sales (USD)</th>
<th scope="col">Growth</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">North America</th>
<td>$1,240,000</td>
<td>+12%</td>
</tr>
</tbody>
<tfoot>
<tr>
<th scope="row">Total</th>
<td>$3,890,000</td>
<td>+8%</td>
</tr>
</tfoot>
</table>
ルール:
- すべてのテーブルにタイトルとして
<caption>を使用します - すべてのヘッダーセルに
<th scope="col|row|colgroup|rowgroup">を使用します - 構造化には
<thead>、<tbody>、<tfoot>を使用します - レイアウトにテーブルを使用せず、代わりに CSS Grid/Flexbox を使用します
パート 6 — アクセシビリティを考慮したデザイン:フロントエンドの美的ガイドライン
6.1 アクセシブルなインターフェースのデザイン思考
コーディングを始める前に、アクセシビリティを考慮しながら、大胆で意図の明確な美的方向性を決めてください。
- 目的:どのような問題を解決しますか?誰が使いますか?ユーザーにはどのような障害がある可能性がありますか?
- トーン:極端な美的方向性を選びます。徹底したミニマル、タイポグラフィを重視したマキシマリズム、オーガニック/ナチュラル、エディトリアル、ブルータリスト、レトロフューチャー、ラグジュアリー/洗練、遊び心のあるもの、インダストリアルなど。
- 制約:フレームワーク、パフォーマンス、WCAG の適合レベル(AA を目標)、コントラスト要件
- 差別化:忘れられないデザインとアクセシビリティを両立させるには?大胆なデザインと WCAG は両立します。
**アクセシビリティはデザインの指針であり、制約ではありません。**優れたアクセシブルなデザインには、次のような特徴があります。
- 色の強いコントラストを、欠点ではなくデザイン要素として活用する
- 明確なタイポグラフィの階層を、ビジュアルシステムとして活用する
- 視認できるフォーカス状態を、意図的なデザイン要素として取り入れる
- セマンティックな構造を、構成の論理として活用する
6.2 アクセシビリティを考慮したカラ―システムのデザイン
アクセシブルなカラ―システムをデザインします。
:root {
/* Accessible palette using HSL for easier contrast calculation */
--color-bg: hsl(220, 15%, 10%); /* Near-black background */
--color-surface: hsl(220, 12%, 15%); /* Elevated surface */
--color-border: hsl(220, 10%, 25%); /* Subtle border */
--color-text-primary: hsl(220, 10%, 95%); /* High contrast text: >7:1 */
--color-text-secondary: hsl(220, 8%, 70%); /* Medium contrast: ~4.5:1 */
--color-text-muted: hsl(220, 6%, 55%); /* Low contrast: ~3:1 (large text only) */
--color-accent: hsl(210, 100%, 65%); /* Action color: verify contrast */
--color-accent-hover: hsl(210, 100%, 72%); /* Hover state */
--color-error: hsl(0, 80%, 65%); /* Error — verify 4.5:1 on bg */
--color-success: hsl(145, 60%, 55%); /* Success — verify 4.5:1 on bg */
--color-warning: hsl(45, 90%, 55%); /* Warning — verify 4.5:1 on bg */
/* Focus ring — must contrast 3:1 with adjacent colors (WCAG 2.4.7) */
--color-focus: hsl(210, 100%, 65%);
--focus-ring: 0 0 0 3px var(--color-focus);
}
/* ✅ Color-scheme support */
@media (prefers-color-scheme: light) {
:root {
--color-bg: hsl(0, 0%, 99%);
--color-text-primary: hsl(220, 20%, 8%);
/* ... recalculate all contrasts */
}
}
複数の方法による情報伝達(色だけに頼らないでください)。
/* ❌ Color only for error */
.input-error { border-color: red; }
/* ✅ Color + icon + text + pattern */
.input-error {
border-color: var(--color-error);
border-width: 2px;
background-image: url("error-icon.svg");
background-position: right 12px center;
background-repeat: no-repeat;
padding-right: 40px;
}
6.3 タイポグラフィのデザインシステム
/* ✅ Accessible, distinctive type scale */
:root {
/* Scale: Major Third (1.25) or Perfect Fourth (1.333) */
--text-xs: 0.75rem; /* 12px — captions, labels */
--text-sm: 0.875rem; /* 14px — secondary text */
--text-base: 1rem; /* 16px — body */
--text-lg: 1.125rem; /* 18px — lead text */
--text-xl: 1.25rem; /* 20px */
--text-2xl: 1.5rem; /* 24px */
--text-3xl: 1.875rem; /* 30px */
--text-4xl: 2.25rem; /* 36px */
--text-5xl: 3rem; /* 48px */
--text-6xl: 3.75rem; /* 60px */
/* Accessible line heights */
--leading-tight: 1.25;
--leading-snug: 1.375;
--leading-normal: 1.5;
--leading-relaxed:1.625;
--leading-loose: 2;
/* Weights */
--font-light: 300; /* Use sparingly, large sizes only */
--font-normal: 400;
--font-medium: 500;
--font-semibold: 600;
--font-bold: 700;
--font-black: 900;
}
独自性とアクセシビリティを両立するフォントの選び方:
- ディスプレイ用途では Inter、Roboto、Arial、system-ui を避けます。汎用的すぎるためです。
- 光学サイズの幅が広い書体を選びます。DM Sans、Fraunces、Bricolage Grotesque、 Playfair Display、Syne、General Sans、Cabinet Grotesk、Instrument Serif などです。
- 個性のあるディスプレイフォントには、すっきりと読みやすい本文用フォントを組み合わせます。
- 選んだフォントが本文のサイズ(14–18px)でも読みやすく表示されることを確認します。
- 常に読みやすいフォールバック用フォントスタックを用意します。
6.4 デザイン要素としてのフォーカスインジケーター
フォーカスインジケーターを後付けにせず、意図的なデザイン要素にします。
/* Option 1: Solid outline */
:focus-visible {
outline: 3px solid var(--color-accent);
outline-offset: 3px;
border-radius: var(--radius-sm, 4px);
}
/* Option 2: Box shadow (inset for contained elements) */
:focus-visible {
outline: none;
box-shadow: 0 0 0 3px var(--color-bg), 0 0 0 5px var(--color-accent);
}
/* Option 3: High visibility for text links */
a:focus-visible {
outline: none;
background-color: var(--color-accent);
color: var(--color-bg);
text-decoration: none;
border-radius: 2px;
padding: 0 2px;
}
/* Verify contrast: focused vs unfocused → must be ≥3:1 change */
6.5 運動機能のアクセシビリティを考慮した間隔とレイアウト
/* ✅ Generous interactive targets */
.btn {
/* Minimum visually 44×44 (WCAG 2.5.5 AAA) */
min-height: 44px;
padding-inline: 1.25rem;
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
/* ✅ Inline links — guaranteed minimum height */
a {
display: inline-block; /* Ensures tap area */
padding: 0.25em 0;
}
/* ✅ Spacing between small targets (WCAG 2.5.8 AA) */
.icon-group { gap: 0.5rem; } /* 8px between 24px targets = sufficient */
/* ✅ Grid and flex for logical order */
/* Visual order must match DOM order for keyboard/screen reader users */
/* Avoid using CSS `order` property to reorder visual layout */
6.6 アクセシブルなアニメーションのデザイン
/* ✅ Always implement reduced-motion alternative */
:root {
--duration-fast: 150ms;
--duration-base: 250ms;
--duration-slow: 400ms;
--easing-out: cubic-bezier(0.16, 1, 0.3, 1);
}
@media (prefers-reduced-motion: reduce) {
:root {
--duration-fast: 0ms;
--duration-base: 0ms;
--duration-slow: 0ms;
}
}
/* ✅ Purpose-driven micro-interactions */
.btn {
transition:
background-color var(--duration-fast) ease,
transform var(--duration-fast) var(--easing-out),
box-shadow var(--duration-fast) ease;
}
.btn:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
.btn:active {
transform: translateY(0);
box-shadow: none;
}
パート 7 — テストチェックリスト
クイック監査(5 分)
- ページ全体を Tab キーで移動し、すべての要素に移動して操作できることを確認します。
- フォーカスインジケーターが常に表示されていますか?
- ブラウザーの DevTools で色のコントラストを確認します。
- axe DevTools または Lighthouse のアクセシビリティ監査を実行します。
- CSS を無効にしてページを確認します(セマンティックな構造が見えますか?)。
標準監査(WCAG 2.2 AA)
知覚可能
- すべての画像に意味のある代替テキストがある(装飾目的の場合は
alt=""を指定) - 色のコントラスト比が、通常のテキストで 4.5:1 以上、大きなテキストと UI 要素で 3:1 以上
- 情報を伝える方法が色だけに依存していない
- 200% のズームでもコンテンツが読みやすく、機能する
- 幅 320px で横スクロールが発生しない(リフロー)
- テキスト間隔の変更によってレイアウトが崩れない
- 操作コントロールなしで音声が自動再生されない
操作可能
- すべての機能をキーボードで操作できる
- キーボードトラップがない
- フォーカスインジケーターが常に見える
- 固定ヘッダー/フッターによってフォーカスが隠れない
- ナビゲーションをスキップするリンクがある
- すべてのページに内容を説明する
<title>がある - フォーカス順序が論理的である
- リンクのテキストが明確で、内容を説明している
- タッチターゲットが 24×24px 以上で、適切な間隔がある
- 1 秒間に 3 回を超える点滅コンテンツがない
理解可能
-
<html lang="en">が正しく設定されている - 言語の変更が
lang属性で示されている - フォーカス時に予期しないコンテキストの変化がない
- ページ間でナビゲーションに一貫性がある
- すべてのフォーム入力に視認できるラベルがある
- エラーが特定され、説明され、対処方法が提示されている
- ヘルプ機能が一貫した場所にある
堅牢
- すべてのフォームコントロールに、HTML または ARIA を通じて名前、ロール、値が設定されている
- ステータスメッセージが、フォーカスを移動せずに読み上げられる
- HTML が有効で、適切に構成されている(入れ子構造が壊れていない)
- ARIA のロール/状態が正しく使用されている
- 動的なコンテンツの更新が読み上げられる
スクリーンリーダーでのテスト
次の組み合わせでテストします:NVDA + Chrome(Windows)、VoiceOver + Safari(Mac)、TalkBack + Chrome(Android)
- 見出しの構造が論理的で、順に移動できる
- ランドマーク(nav、main、aside、footer)間を移動できる
- フォームのラベルが正しく読み上げられる
- 入力欄が無効な場合、エラーメッセージが読み上げられる
- 動的コンテンツ(アラート、ステータス)が読み上げられる
- モーダル:フォーカスが閉じ込められ、Escape で閉じ、フォーカスが元の位置に戻る
パート 8 — 法律と規格の背景
| 規格 | 適用地域 | 基準 |
|---|---|---|
| ADA (Americans with Disabilities Act) | USA | WCAG 2.1 AA |
| Section 508 | USA (Federal) | WCAG 2.0 AA |
| EN 301 549 | European Union | WCAG 2.1 AA |
| AODA | Ontario, Canada | WCAG 2.0 AA |
| Equality Act 2010 | UK | WCAG 2.1 AA |
| BS 8878 | UK | WCAG 2.1 |
| BITV 2.0 | Germany | WCAG 2.1 AA |
推奨目標:WCAG 2.2 AA — 主要な法律の要件をすべて上回り、将来にも対応できます。
パート 9 — ツールとリソース
テストツール
| ツール | 種類 | 用途 |
|---|---|---|
| axe DevTools | ブラウザー拡張機能 + CI | 最も包括的な自動チェック |
| WAVE (WebAIM) | ブラウザー拡張機能 | エラーを視覚的にオーバーレイ表示 |
| Lighthouse | Chrome DevTools | 簡易的な初期監査 |
| Colour Contrast Analyser | デスクトップアプリ | ピクセル単位で正確なコントラストチェック |
| WebAIM Contrast Checker | ウェブツール | コントラストをすばやく計算 |
| NVDA | スクリーンリーダー | Windows でのスクリーンリーダーテスト(無料) |
| VoiceOver | スクリーンリーダー | Mac/iOS に組み込み |
| TalkBack | スクリーンリーダー | Android に組み込み |
| Keyboard | 手動 | キーボードのみでのナビゲーションを必ずテスト |
主な参考資料
- WCAG 2.2 Specification:https://www.w3.org/TR/WCAG22/
- WAI-ARIA Authoring Practices Guide:https://www.w3.org/WAI/ARIA/apg/
- WebAIM Articles:https://webaim.org/articles/
- The A11Y Project:https://www.a11yproject.com/
- Deque University:https://dequeuniversity.com/
- MDN Accessibility:https://developer.mozilla.org/en-US/docs/Web/Accessibility
- Inclusive Components (Heydon Pickering):https://inclusive-components.design/
- A11y Coffee:https://a11y.coffee/
まとめ:譲れない AA ルール
フロントエンドのインターフェースを構築する際は、次の WCAG 2.2 AA ルールを常に満たす必要があります。
- コントラスト:通常のテキストは 4.5:1、大きなテキストと UI コンポーネントは 3:1
- 代替テキスト:情報を伝える画像すべてに説明的な代替テキストを付け、装飾画像には
alt=""を指定する - キーボード:すべての機能にキーボードのみでアクセスし、操作できる
- フォーカスの可視化:常に表示され、決して削除されないフォーカスインジケーターを用意する
- ラベル:すべてのフォーム入力欄に、関連付けられた可視の
<label>を付ける - エラー:エラーは色だけでなくテキストでも特定できるようにし、aria-invalid を使用して、解決策を提示する
- 見出し:論理的な階層にし、レベルを飛ばさない
- 言語:
<html lang="...">を必ず設定する - セマンティック HTML:
<div>で代用せず、<button>、<a>、<nav>、<main>などを使う - 色だけで情報を伝えない:情報を伝える唯一の手段として色を使わない
- リフロー:横スクロールなしで、幅 320px でもコンテンツを利用できる
- タッチターゲット:操作可能な要素は 24×24px 以上にするか、十分な間隔を確保する
- フォーカスを隠さない:固定ヘッダーやフッターが、フォーカスのある要素を隠さない
- ステータスメッセージ:動的なステータスやエラーメッセージをスクリーンリーダーで読み上げる
- 一貫したヘルプ:各ページで、ヘルプ機能を同じ位置に配置する