Web全般

Webアクセシビリティ入門|すべての人が使えるサイトを作る

Web アクセシビリティ WCAG

Webアクセシビリティ入門
すべての人が使えるサイトを作る

Webアクセシビリティの基本原則から、セマンティックHTML、ARIA属性、キーボード操作、チェックツールまで、実践的な対応方法を解説します。

こんな人向けの記事です

  • Webアクセシビリティの基本を学びたい
  • WCAG準拠のサイトを作りたい
  • ARIA属性の使い方を知りたい

Step 1アクセシビリティとは(WCAG概要)

Webアクセシビリティ(a11y)とは、障害のある人や高齢者を含むすべてのユーザーがWebサイトを利用できるようにすることです。視覚・聴覚・運動・認知など、さまざまな障害を持つ人がWebを使えるように配慮します。

アクセシビリティの国際基準として WCAG(Web Content Accessibility Guidelines) があります。W3Cが策定しており、多くの国の法規制の基盤となっています。

WCAGは4つの原則に基づいています:

原則英語概要
知覚可能Perceivable情報やUIコンポーネントをユーザーが知覚できること
操作可能OperableUIコンポーネントやナビゲーションを操作できること
理解可能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> で何でも囲んでしまうケースがあります。これではマシンがコンテンツの意味を判断できません。

HTML(悪い例)
<!-- 悪い例: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>
HTML(良い例)
<!-- 良い例:セマンティック要素を使用 -->
<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 テキストを読み上げて、画像の内容をユーザーに伝えます。

HTML
<!-- 情報を伝える画像:具体的な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だけでは伝えきれないアクセシビリティ情報を補足するための属性群です。

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
ARIAの第一ルール

「ネイティブのHTML要素や属性で目的を達成できるなら、ARIAを使わない」が原則です。例えば <div role="button"> より <button> を使いましょう。ネイティブ要素にはキーボード操作やフォーカス管理が組み込まれています。

Step 4キーボードナビゲーション

マウスが使えないユーザーはキーボードだけで操作します。すべてのインタラクティブ要素にキーボードでアクセスできることは、アクセシビリティの必須要件です。

基本的なキーボード操作:

キー動作
Tab次のインタラクティブ要素にフォーカス移動
Shift + Tab前のインタラクティブ要素にフォーカス移動
Enterリンクのクリック、ボタンの実行
Spaceボタンの実行、チェックボックスの切り替え
Escapeモーダルやドロップダウンを閉じる
矢印キーラジオボタン・タブ・メニュー内の移動

フォーカス管理

CSS
/* フォーカスインジケータを消さない! */
/* 悪い例 */
*: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;
}
HTML
<!-- スキップリンク:キーボードユーザーがナビを飛ばせる -->
<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 以上
CSS
/* 良い例:十分なコントラスト */
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; /* ユーザー設定に追従 */
}

読みやすさに関するチェックポイント:

  • テキストは remem で指定し、ブラウザの拡大設定を尊重する
  • 行間(line-height)は 1.5以上 を推奨
  • 段落間の余白はフォントサイズの 1.5倍以上
  • テキストの横幅は 80文字以内 が読みやすい
  • テキスト間隔の変更をユーザーに許可する(!important でのスタイル上書きを妨げない)
コントラスト比の確認方法

Chrome DevToolsで要素を選択すると、コントラスト比が表示されます。色の横にある丸いアイコンをクリックすると、WCAG AA/AAAの合格・不合格がわかります。

Step 6アクセシビリティチェックツール

アクセシビリティの問題を効率的に発見するために、チェックツールを活用しましょう。自動テストで検出できるのは全体の約30%ですが、基本的な問題は見つけられます。

ブラウザ拡張機能

ツール特徴おすすめ度
axe DevToolsDeque社提供。Chrome DevToolsに統合。問題の詳細と修正方法を表示必須
LighthouseChrome内蔵。パフォーマンス・SEOと一緒にa11yも監査必須
WAVEWebAIM提供。ページ上に問題箇所を視覚的に表示おすすめ
HeadingsMap見出し構造を一覧表示。見出しの階層ミスを発見補助的

コマンドラインツール

bash
# 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に組み込む

.github/workflows/a11y.yml
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%にしてもレイアウトが崩れないか
  • 色だけに依存した情報伝達をしていないか
  • 動画に字幕・音声に代替テキストがあるか
  • フォームのエラーメッセージが適切に伝わるか
まずは「レベルAA」を目標に

すべてを一度に完璧にする必要はありません。まずは WCAG 2.1 レベルAA を目標に、影響の大きい問題から順に対応していきましょう。alt属性の設定、キーボード操作の確保、コントラスト比の改善は、すぐに取り組めて効果の大きい項目です。

まとめ

  • Webアクセシビリティは障害の有無にかかわらず、すべてのユーザーがサイトを利用できるようにすること
  • WCAGの4原則(知覚可能・操作可能・理解可能・堅牢)を意識して実装する
  • セマンティックHTMLが土台。<div> の乱用を避け、適切な要素を選ぶ
  • 画像には目的に応じた alt 属性を必ず設定する
  • ARIA属性はネイティブHTML要素で対応できない場合にのみ使う
  • キーボードだけで全機能を操作でき、フォーカスが常に見えること
  • テキストのコントラスト比はAA基準(4.5:1)以上を確保する
  • フォントサイズは rem で指定し、ユーザーの設定を尊重する
  • axe DevTools・Lighthouse等のツールを使い、CI/CDにも組み込む
  • 自動テストで検出できるのは約30%。手動チェックも定期的に行う