Webアクセシビリティ入門
すべての人が使えるサイトを作る
Webアクセシビリティの基本原則から、セマンティックHTML、ARIA属性、キーボード操作、チェックツールまで、実践的な対応方法を解説します。
こんな人向けの記事です
- Webアクセシビリティの基本を学びたい
- WCAG準拠のサイトを作りたい
- ARIA属性の使い方を知りたい
Step 1アクセシビリティとは(WCAG概要)
Webアクセシビリティ(a11y)とは、障害のある人や高齢者を含むすべてのユーザーがWebサイトを利用できるようにすることです。視覚・聴覚・運動・認知など、さまざまな障害を持つ人がWebを使えるように配慮します。
アクセシビリティの国際基準として WCAG(Web Content Accessibility Guidelines) があります。W3Cが策定しており、多くの国の法規制の基盤となっています。
WCAGは4つの原則に基づいています:
| 原則 | 英語 | 概要 |
|---|---|---|
| 知覚可能 | Perceivable | 情報やUIコンポーネントをユーザーが知覚できること |
| 操作可能 | Operable | UIコンポーネントやナビゲーションを操作できること |
| 理解可能 | Understandable | 情報やUIの操作方法を理解できること |
| 堅牢 | Robust | さまざまな支援技術で確実に解釈できること |
WCAGには3つの適合レベルがあります:
- レベルA — 最低限のアクセシビリティ。すべてのサイトが満たすべき基準
- レベルAA — 推奨レベル。多くの法規制で要求される基準
- レベルAAA — 最高レベル。全ページでの達成は困難だが、可能な限り目指すべき基準
日本では2024年4月に改正障害者差別解消法が施行され、民間事業者にも合理的配慮の提供が義務化されました。Webサイトのアクセシビリティ対応は法的にも重要性が増しています。JIS X 8341-3はWCAG 2.0/2.1と一致しています。
Step 2セマンティックHTMLの重要性
セマンティックHTMLはアクセシビリティの土台です。適切なHTML要素を使うことで、スクリーンリーダーなどの支援技術がページの構造を正しく理解できます。
よくある問題として、<div> や <span> で何でも囲んでしまうケースがあります。これではマシンがコンテンツの意味を判断できません。
<!-- 悪い例:divで全てを構成 -->
<div class="header">
<div class="title">サイト名</div>
</div>
<div class="nav">
<div class="link">ホーム</div>
<div class="link">お問い合わせ</div>
</div>
<div class="content">
<div class="article-title">記事タイトル</div>
<div class="text">本文...</div>
</div>
<!-- 良い例:セマンティック要素を使用 -->
<header>
<h1>サイト名</h1>
</header>
<nav>
<ul>
<li><a href="/">ホーム</a></li>
<li><a href="/contact">お問い合わせ</a></li>
</ul>
</nav>
<main>
<article>
<h2>記事タイトル</h2>
<p>本文...</p>
</article>
</main>
特にアクセシビリティの観点で重要な要素を整理します:
| 要素 | 用途 | a11yへの効果 |
|---|---|---|
<h1>〜<h6> | 見出し階層 | スクリーンリーダーが見出しジャンプで移動可能 |
<nav> | ナビゲーション | 支援技術がナビゲーション領域を認識 |
<main> | メインコンテンツ | スキップリンクの対象になる |
<button> | ボタン | キーボード操作・フォーカスが自動で有効 |
<label> | フォームラベル | 入力欄とラベルの関連付けを支援技術に伝達 |
<table> + <th> | データテーブル | セルと見出しの関係を支援技術が認識 |
見出しは <h1> → <h2> → <h3> のように順番に使いましょう。<h1> の次にいきなり <h4> を使うと、スクリーンリーダーのユーザーがページ構造を把握しにくくなります。
Step 3画像のalt属性とARIA属性
画像には必ず alt 属性をつけましょう。スクリーンリーダーは alt テキストを読み上げて、画像の内容をユーザーに伝えます。
<!-- 情報を伝える画像:具体的なaltを記述 -->
<img src="chart.png" alt="2025年のアクセス数推移グラフ。1月から12月まで右肩上がり">
<!-- 装飾目的の画像:空のaltを設定 -->
<img src="divider.png" alt="">
<!-- アイコン付きリンク:altで補足しない(テキストがあるため) -->
<a href="/home">
<img src="home-icon.svg" alt="">
ホーム
</a>
<!-- アイコンのみのボタン:altで説明が必要 -->
<button>
<img src="search-icon.svg" alt="検索">
</button>
alt 属性の書き方のポイント:
- 画像が伝える情報を簡潔に書く(「画像」「写真」は不要)
- 装飾目的の画像は
alt=""(空文字)にする - グラフや図は、データの要点を
altに含める alt属性自体を省略してはいけない
ARIA属性
ARIA(Accessible Rich Internet Applications)は、HTMLだけでは伝えきれないアクセシビリティ情報を補足するための属性群です。
<!-- aria-label: 要素にラベルを付与 -->
<button aria-label="メニューを閉じる">
<svg>...</svg> <!-- xアイコン -->
</button>
<!-- aria-hidden: 支援技術から隠す(装飾要素に使用) -->
<span aria-hidden="true">★</span>
<span class="sr-only">お気に入り</span>
<!-- aria-expanded: 開閉状態を通知 -->
<button aria-expanded="false" aria-controls="menu">
メニュー
</button>
<ul id="menu" hidden>
<li>項目1</li>
<li>項目2</li>
</ul>
<!-- aria-live: 動的コンテンツの変更を通知 -->
<div aria-live="polite">
<!-- ここに挿入されたメッセージが読み上げられる -->
</div>
<!-- role: 要素の役割を明示(ネイティブ要素推奨) -->
<div role="alert">エラーが発生しました</div>
主要なARIA属性の一覧です:
| 属性 | 用途 | 使用例 |
|---|---|---|
aria-label | 要素にラベルを付与 | アイコンボタン、検索フォーム |
aria-labelledby | 他の要素のIDでラベルを参照 | モーダルのタイトル参照 |
aria-describedby | 補足説明を参照 | 入力欄のエラーメッセージ |
aria-hidden | 支援技術から非表示 | 装飾アイコン、重複コンテンツ |
aria-expanded | 開閉状態を通知 | アコーディオン、ドロップダウン |
aria-live | 動的変更を通知 | 通知メッセージ、チャット |
role | 要素の役割を明示 | alert、dialog、tablist |
「ネイティブのHTML要素や属性で目的を達成できるなら、ARIAを使わない」が原則です。例えば <div role="button"> より <button> を使いましょう。ネイティブ要素にはキーボード操作やフォーカス管理が組み込まれています。
Step 4キーボードナビゲーション
マウスが使えないユーザーはキーボードだけで操作します。すべてのインタラクティブ要素にキーボードでアクセスできることは、アクセシビリティの必須要件です。
基本的なキーボード操作:
| キー | 動作 |
|---|---|
Tab | 次のインタラクティブ要素にフォーカス移動 |
Shift + Tab | 前のインタラクティブ要素にフォーカス移動 |
Enter | リンクのクリック、ボタンの実行 |
Space | ボタンの実行、チェックボックスの切り替え |
Escape | モーダルやドロップダウンを閉じる |
矢印キー | ラジオボタン・タブ・メニュー内の移動 |
フォーカス管理
/* フォーカスインジケータを消さない! */
/* 悪い例 */
*:focus {
outline: none; /* 絶対にやめましょう */
}
/* 良い例:カスタムフォーカススタイル */
:focus-visible {
outline: 3px solid #4A90D9;
outline-offset: 2px;
border-radius: 2px;
}
/* スキップリンク(メインコンテンツへジャンプ) */
.skip-link {
position: absolute;
top: -40px;
left: 0;
padding: 8px 16px;
background: #000;
color: #fff;
z-index: 100;
transition: top 0.2s;
}
.skip-link:focus {
top: 0;
}
<!-- スキップリンク:キーボードユーザーがナビを飛ばせる -->
<body>
<a href="#main-content" class="skip-link">
メインコンテンツへスキップ
</a>
<header>...</header>
<nav>...</nav>
<main id="main-content">...</main>
</body>
<!-- tabindex の使い方 -->
<!-- tabindex="0" : 自然な順序でフォーカス可能にする -->
<div tabindex="0" role="button" onclick="toggle()">
クリック可能なカスタム要素
</div>
<!-- tabindex="-1" : JSでフォーカス可能だがTab順には含まない -->
<div id="modal" tabindex="-1" role="dialog">
<!-- モーダルを開いた時にJSでfocus()する -->
</div>
<!-- tabindex="1"以上 : 使わない!(順序が壊れる) -->
モーダルダイアログでは「フォーカストラップ」を実装しましょう。モーダルが開いている間、Tabキーでのフォーカス移動をモーダル内に閉じ込めます。背景のコンテンツにフォーカスが移ると、モーダルの存在がわからなくなります。
Step 5コントラスト比とフォントサイズ
テキストの読みやすさは視覚的なアクセシビリティの基本です。WCAGではコントラスト比の基準が定められています。
| 対象 | レベルAA | レベルAAA |
|---|---|---|
| 通常テキスト(18px未満) | 4.5:1 以上 | 7:1 以上 |
| 大きいテキスト(18px以上 or 14px太字) | 3:1 以上 | 4.5:1 以上 |
| UIコンポーネント・グラフィック | 3:1 以上 | — |
/* 良い例:十分なコントラスト */
body {
color: #333; /* 白背景に対して 12.6:1 */
background: #fff;
}
a {
color: #0056b3; /* 白背景に対して 7.2:1 */
}
/* 悪い例:コントラスト不足 */
.light-text {
color: #aaa; /* 白背景に対して 2.3:1(不合格) */
}
.placeholder {
color: #ccc; /* 白背景に対して 1.6:1(不合格) */
}
/* フォントサイズとレスポンシブ対応 */
html {
font-size: 100%; /* ユーザーの設定を尊重(通常16px) */
}
body {
font-size: 1rem; /* px固定ではなくremを使用 */
line-height: 1.6; /* 行間を十分に確保 */
}
h1 { font-size: 2rem; }
h2 { font-size: 1.5rem; }
/* pxでフォントサイズを固定しない */
/* 悪い例 */
.fixed-text {
font-size: 12px; /* ブラウザの拡大設定が効かない */
}
/* 良い例 */
.flexible-text {
font-size: 0.875rem; /* ユーザー設定に追従 */
}
読みやすさに関するチェックポイント:
- テキストは
remやemで指定し、ブラウザの拡大設定を尊重する - 行間(
line-height)は 1.5以上 を推奨 - 段落間の余白はフォントサイズの 1.5倍以上
- テキストの横幅は 80文字以内 が読みやすい
- テキスト間隔の変更をユーザーに許可する(
!importantでのスタイル上書きを妨げない)
Chrome DevToolsで要素を選択すると、コントラスト比が表示されます。色の横にある丸いアイコンをクリックすると、WCAG AA/AAAの合格・不合格がわかります。
Step 6アクセシビリティチェックツール
アクセシビリティの問題を効率的に発見するために、チェックツールを活用しましょう。自動テストで検出できるのは全体の約30%ですが、基本的な問題は見つけられます。
ブラウザ拡張機能
| ツール | 特徴 | おすすめ度 |
|---|---|---|
| axe DevTools | Deque社提供。Chrome DevToolsに統合。問題の詳細と修正方法を表示 | 必須 |
| Lighthouse | Chrome内蔵。パフォーマンス・SEOと一緒にa11yも監査 | 必須 |
| WAVE | WebAIM提供。ページ上に問題箇所を視覚的に表示 | おすすめ |
| HeadingsMap | 見出し構造を一覧表示。見出しの階層ミスを発見 | 補助的 |
コマンドラインツール
# axe-core をコマンドラインで実行
npm install -g @axe-core/cli
axe https://example.com --tags wcag2a,wcag2aa
# Pa11y:シンプルなa11yテスト
npm install -g pa11y
pa11y https://example.com
# Pa11y CI:複数ページを一括テスト
npm install -g pa11y-ci
pa11y-ci --config .pa11yci.json
CI/CDに組み込む
name: Accessibility Check
on: [push, pull_request]
jobs:
a11y:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Install Pa11y
run: npm install -g pa11y-ci
- name: Start server
run: npm start &
- name: Run accessibility tests
run: pa11y-ci --config .pa11yci.json
手動テストも忘れずに
自動テストだけでは不十分です。以下の手動チェックも定期的に行いましょう:
アクセシビリティチェックリスト
- キーボードだけですべての機能を操作できるか
- フォーカスインジケータが常に見えるか
- スクリーンリーダー(VoiceOver / NVDA)で内容が理解できるか
- ブラウザの文字サイズを200%にしてもレイアウトが崩れないか
- 色だけに依存した情報伝達をしていないか
- 動画に字幕・音声に代替テキストがあるか
- フォームのエラーメッセージが適切に伝わるか
すべてを一度に完璧にする必要はありません。まずは WCAG 2.1 レベルAA を目標に、影響の大きい問題から順に対応していきましょう。alt属性の設定、キーボード操作の確保、コントラスト比の改善は、すぐに取り組めて効果の大きい項目です。
まとめ
- Webアクセシビリティは障害の有無にかかわらず、すべてのユーザーがサイトを利用できるようにすること
- WCAGの4原則(知覚可能・操作可能・理解可能・堅牢)を意識して実装する
- セマンティックHTMLが土台。
<div>の乱用を避け、適切な要素を選ぶ - 画像には目的に応じた
alt属性を必ず設定する - ARIA属性はネイティブHTML要素で対応できない場合にのみ使う
- キーボードだけで全機能を操作でき、フォーカスが常に見えること
- テキストのコントラスト比はAA基準(4.5:1)以上を確保する
- フォントサイズは
remで指定し、ユーザーの設定を尊重する - axe DevTools・Lighthouse等のツールを使い、CI/CDにも組み込む
- 自動テストで検出できるのは約30%。手動チェックも定期的に行う