スクリーンリーダ

画面の内容を音声で読み上げる支援技術。a11y を「実際の体験」として理解するには、 1度は自分で触ってみるのが一番早い。10分でメンタルモデルが変わる。

主要なスクリーンリーダ

名前OS備考
NVDAWindows無料・OSS。普及シェア No.1。
JAWSWindows有料。企業利用が多い。
NarratorWindowsOS 標準。
VoiceOvermacOS / iOSOS 標準。Cmd+F5 で起動。
TalkBackAndroidOS 標準。
OrcaLinuxOS 標準。

テストのためなら、VoiceOver(Mac)と NVDA(Windows)のどちらかが触れれば十分。

仕組み: アクセシビリティツリー

ブラウザは DOM をもとにアクセシビリティツリーを構築する。スクリーンリーダは DOM ではなくこのツリーを介してページを「読む」。

ツリーの各ノードは少なくとも以下を持つ:

Chrome DevTools の Elements パネル → Accessibility タブで実際のツリーが見える。 「自分の HTML が支援技術にどう見えているか」を確認できる。

SR ユーザーの読み方

視覚ユーザーがページを上から下に読むのと違い、SR 利用者はジャンプ機能を多用する。

だから「見出しがないページ」「意味のない見出し階層」「ランドマークがない」は 極端に使いにくくなる。

Mac VoiceOver 入門

とりあえず触ってみるならこれ。Cmd+F5 で ON/OFF。 Caps Lock はVoiceOver キー(VO)として使う(システム環境設定で設定)。

キー動作
VO+ / 次/前の要素へ移動
VO+Spaceクリック
VO+Uローター(リンク・見出し一覧)を開く
VO+Cmd+H次の見出し
VO+Cmd+L次のリンク
Ctrl読み上げを止める
VO+Aページ全体を読み上げ

Safari + VoiceOver の組み合わせが一番安定。Chrome でもだいたい動く。

NVDA 入門(Windows)

無料で 公式サイトから DL。Insert キーを NVDA キーとして使う("NVDA")。

キー動作
/ 次/前の行(ブラウズモード)
H次の見出し
K次のリンク
F次のフォームコントロール
D次のランドマーク
NVDA+F7要素一覧(リンク・見出し・ランドマーク)
NVDA+Downそこから読み上げ
Ctrl停止

「見えない」と「読まれない」の違い

方法視覚的に見えるSR が読み上げフォーカス可能
display: none×××
visibility: hidden×××
opacity: 0×
hidden 属性×××
aria-hidden="true"×○(要注意)
inert 属性××
.sr-only CSS×

モーダル背景は inert、装飾アイコンは aria-hidden="true"、 SR専用テキストは .sr-only ─ と用途で使い分ける。

ライブリージョン

ページの一部が動的に変わった時、SR にそれを通知する仕組み。 例: 「保存しました」のトースト、検索結果の件数表示、エラー通知。

aria-live の3段階

専用 role を使う方が楽

role同等の aria-live用途
role="status"polite状態通知("保存しました")
role="alert"assertive緊急("エラー")
role="log"polite追加されていくログ(チャット)
role="timer"offタイマー
role="marquee"offスクロールテキスト
<!-- 保存通知 -->
<div role="status">変更を保存しました</div>

<!-- エラー -->
<div role="alert">接続に失敗しました</div>

動的に追加すること

あらかじめ live region のコンテナを置いておき、中身を後から書き換えるのが安定パターン。 コンテナを後から DOM に挿入すると、SR が見落とすことがある。

<!-- 最初から空で置いておく -->
<div id="status" role="status"></div>

<script>
  document.getElementById("status").textContent = "保存しました"
</script>

連続して同じ文言を出すと無視されることがある

SR は「同じ文字列の更新」を変化なしとみなして読み上げないことがある。 テキストを一度クリアしてから入れ直すと確実。

SPA でのページ遷移通知

SPA はクライアントサイドルーティング。ブラウザの「ページ読み込み完了」イベントが発火しないので、 SR は「ページが変わった」ことに気付けない。

対策:

// React Router 等を使うフレームワークではビルトインの focus 管理が望ましい

// 自前で書く時の最小例
function onRouteChange(title) {
  document.title = title
  const main = document.querySelector("main")
  main.setAttribute("tabindex", "-1")
  main.focus()
}

テストの仕方

最低限のチェック

  1. SR を ON にしてページを開く。タイトルが読まれるか。
  2. Tab で全要素に到達できるか。読み上げ内容に違和感がないか。
  3. 見出しジャンプ(H キー / VO+Cmd+H)でページ構造が伝わるか。
  4. ランドマークジャンプでヘッダ・main・フッタが認識できるか。
  5. フォームをSR で実際に入力。ラベル・必須・エラーが伝わるか。
  6. モーダルや menu を開いた時、フォーカスが正しく移っているか
  7. 動的更新(保存通知等)が読み上げられるか。

Chrome DevTools の Accessibility パネル

要素を選んだ状態でElements → Accessibility。Name / Role / State が 意図通りになっているか確認できる。SR を起動しなくても素早くチェックできる。

SR の使い方は最初は怖い

初めて SR を ON にすると、画面が読み上げられて「どこに何があるかわからない」状態になる。 これが多くの SR 利用者の毎日の体験
まずは自分のサイトで何回か触って慣れる。それだけで a11y への理解が劇的に深まる。