開発

Webアクセシビリティのスクリーンリーダー対応:NVDA・VoiceOverでの実機検証と読み上げ順序の設計

スクリーンリーダー対応で手が止まるのは、属性の書き方を知らないからではありません。読み上げの順番が画面の見た目とずれる理由、そのずれを自動検証ツールが一切報告しない理由、この2点が見えていないためです。この記事では、読み上げの元データであるアクセシビリティツリーの決まり方、DOM順と視覚順が食い違う条件、NVDA・VoiceOver・TalkBackで確かめる範囲、動的更新の通知設計、実機検証に回す画面の絞り込みを扱います。対応全体の進め方はウェブアクセシビリティ向上の進め方|JIS改正でWCAG 2.2へを参照してください。

まとめ:読み上げ順序の決まり方と、実機検証に回す範囲の線引き

読み上げられる内容は、DOMから生成されるアクセシビリティツリーで決まります。CSSで並べ替えても、この木の順番は変わりません。つまりorderやグリッドの配置指定で見た目を入れ替えた箇所は、視覚順と読み上げ順が食い違ったままになります。まずDOMを正しい順に並べ、CSSでの並べ替えは例外扱いにしてください。

各要素の読み上げは、役割(role)・名前(accessible name)・状態(state)の3つの組み合わせで生成される仕組みです。aria-labelを付けると内包テキストが上書きされ、画面に見えている文言と読み上げが別物になります。名前を後から貼るのではなく、ネイティブ要素の内包テキストやラベル要素で名前が付く構造を先に選ぶほうが事故が減ります。

検証は3環境を横並びに回す必要はありません。受託の初期検証はNVDAとChromeの組み合わせ1本に絞り、モバイル固有のUIを持つ画面だけTalkBackとVoiceOverを足す。自動検証が拾えるのは名前の欠落や属性の矛盾までで、順序が意味を成すか、名前が見えている文言と一致するかは機械判定に載りません。この2点だけを実機に回してください。

アクセシビリティツリーとアクセシブルネーム:読み上げ内容が決まる仕組み

スクリーンリーダーはHTMLソースではなく、ブラウザがDOMとCSSから組み立てたアクセシビリティツリーを読み、その各ノードを音声へ変換しています。

role・name・state の三点で決まる読み上げの最小単位

ノード1つの読み上げは、役割・名前・状態の3点で構成される仕組みです。button要素に「送信」と書いてあれば、NVDAは「送信 ボタン」と読みます。ここにaria-expandedが付けば「送信 ボタン 折りたたみ」のように状態が加わります。

逆に言えば、この3点のどれかが欠けたノードは読み上げが成立しません。よくあるのはアイコンだけのボタンで、名前が空のまま「ボタン」とだけ読まれる形です。SVGのアイコンにaria-hiddenを付けて木から外し、ボタン側に名前を与えるのが基本形になります。

アクセシブルネームの計算順序:aria-labelがテキストを上書きする条件

名前の計算には優先順位があります。aria-labelledbyが最優先で、次にaria-label、次にネイティブの仕組み(label要素の関連付け、要素の内包テキスト)、最後にtitle属性という順です。上位が存在すれば下位は無視されます。

事故が起きるのはここです。ボタンに「詳細を見る」と表示しながらaria-label="製品ページへ移動"を付けると、画面には「詳細を見る」、読み上げは「製品ページへ移動」となります。音声入力で操作する人は見えている文言を発話するため、この不一致は操作不能の直接的な原因です。WCAG 2.2の達成基準2.5.3(ラベル・イン・ネーム)は、見えているラベルの文字列がアクセシブルネームに含まれることを求めています。

aria-labelを使ってよいのは、視覚的なラベルが存在しない要素に限られます。アイコンのみのボタン、繰り返し現れる「もっと見る」リンクの区別、ランドマークの名付け。この3つ以外で使いたくなったら、見えているテキストで名前が付く構造に直せないかを先に検討してください。属性の仕様はWAI-ARIAとは何か?その概要と目的をわかりやすく解説で整理しています。

ネイティブ要素とdivへのrole付与で生じる読み上げ結果の差分

W3CのUsing ARIAが示していた第1ルールは、必要な意味と挙動を備えたネイティブHTML要素があるならそれを使え、というものでした。この文書自体は2026年2月24日付でDiscontinued Draftとなり、現在はARIA Authoring Practices Guideの参照が案内されています。

divにrole="button"を付けた自作ボタンは、読み上げこそ「ボタン」になりますが、キーボードのフォーカス、EnterとSpaceでの発火、無効状態の伝達をすべて自前で書く必要があります。3つのうち1つでも欠ければ、スクリーンリーダー利用者はボタンの存在を知りながら押せません。ネイティブのbutton要素なら、この3つは最初から付いてきます。

もう1つ、フォーカス可能な要素にaria-hidden="true"role="presentation"を付けてはいけません(第4ルール)。木から消えているのにフォーカスは当たるため、読み上げが無音になる位置がタブ順の中に生まれます。axeのaria-hidden-focus規則が検出する典型的な違反です。

DOM順・フォーカス順・読み上げ順のずれと、CSSで起きる並び替え事故

flexのorderとgridの配置指定が読み上げ順を崩す条件

FlexboxのorderプロパティとGridの明示的な配置指定は、視覚上の並びだけを変える指定です。アクセシビリティツリーはDOM順のままなので、画面の左上にあるカードが最後に読まれる状態が起こります。タブキーでの移動順もDOM順に従うため、フォーカスリングが画面上を飛び回る現象も同時に発生します。

並べ替えを使ってよいのは「レスポンシブで縦積みにしたときの順序調整」など、意味の順序を壊さない用途に限ります。それ以外はDOMを直してください。検証は開発者ツールでスタイルシートを止め、上から読んで意味が通るか確かめるだけです。

モーダル表示中に背景が読み上げられ続ける原因とinertでの遮断

自作モーダルでもっとも多い欠陥が、背景コンテンツの遮断漏れです。視覚的にはオーバーレイで隠れていても、木の上では背景の見出しやリンクが残っており、ブラウズモードは画面の重なりを見ないため利用者はモーダルの外へ読み進めてしまいます。

遮断にはHTMLのinert属性を用いるのが基本です。背景側のコンテナに付ければ、木からの除外とフォーカスの遮断が同時に効きます。dialog要素をshowModalで開いた場合は、ブラウザ側が同等の遮断を行うため属性の付け外しが不要になります。自作を続ける理由が無いなら、この要素へ寄せるのが最短です。

見出しレベルの飛びとランドマークの欠落で起きるページ内回遊の断絶

WebAIMのScreen Reader User Survey #10(2023年12月から2024年1月実施、有効回答1,539件)では、長いページで情報を探すときに最初に使う方法として、見出しでのナビゲーションを選んだ回答が71.6%を占めました。見出しは装飾ではなく、目次であり移動手段です。

そのため、h2の次にh4を置くような階層の飛びは、構造の欠落としてそのまま伝わります。文字サイズを合わせたいという理由で見出しレベルを選ぶ実装が残っていれば、CSSで見た目を揃えてレベルは論理どおりに戻してください。

ランドマークも同じ役割を持ちます。headernavmainfooterを置けば、NVDAならDキー、VoiceOverならローターで領域単位の移動ができます。すべてdivで組んだページは、この移動手段が使えません。

NVDA・VoiceOver・TalkBackで確認する範囲と操作の最小セット

NVDAとChromeの組み合わせで押さえるブラウズモードの挙動

NV Accessが配布するNVDAは無償で、2026年8月12日時点の安定版は2026.1.1です。覚える操作は多くありません。上下矢印で1行ずつ読み進め、Hキーで見出し送り、Dキーでランドマーク送り、Fキーでフォーム部品送り、Insert+F7で要素の一覧を開く。この5つで構造の欠落はほぼ判定できます。

もう1点、ブラウズモードとフォーカスモードの切り替わりを理解しておく必要があります。テキスト入力欄に入ると自動でフォーカスモードへ移り、矢印キーが文字送りに変わります。自作のコンボボックスやタブUIでモード遷移が起きないと、キー操作が本文送りとして解釈され部品が操作できません。

VoiceOverのローターとiOSのスワイプ操作で見る読み上げ順

VoiceOverはmacOSとiOSに標準搭載され、Safariとの組み合わせが前提になります。macOSではローター(Control+Option+Uなど)で見出し・リンク・ランドマークの一覧を切り替え、iOSでは2本指の回転操作でローターを切り替えます。

iOSで見るべきは、1本指の右スワイプで進む順序です。これがアクセシビリティツリーの順そのものなので、CSSの並べ替えによる事故はここで露見します。タップ位置と読み上げ位置の一致、画面下部の固定バーによる本文の遮りもここで確認します。

TalkBackで確認するモバイル固有の探索と読み上げの分割

AndroidのTalkBackは、Google Play経由で更新されるAndroidアクセシビリティスイートとして提供されます。端末やOSの版によって細部の操作が変わるため、検証端末の版を記録してから始めてください。

TalkBack特有の確認点は、読み上げ単位の分割です。リーディングコントロールで見出し・リンク・段落などの粒度を切り替えられ、カード型UIをひとまとまりで読むか内部の要素ごとに分けて読むかが変わります。リンクを内包したカードで全体と内部リンクが二重に読まれる構成は、ここで顕在化します。

環境 組み合わせ 主に確認する対象
NVDA Windows+Chrome 構造・名前・モード遷移
VoiceOver macOS/iOS+Safari 読み上げ順・モバイル操作
TalkBack Android+Chrome 読み上げ単位・重複読み

WebAIMの同調査では、主に使うスクリーンリーダーはJAWSが40.5%、NVDAが37.7%、VoiceOverが9.7%でした。JAWSは有償で、NVDAと検出できる欠陥も大きく重なります。納品要件に指定が無いなら初期検証はNVDAに寄せて構いません。なお同調査の第11回は2026年8月31日まで回答受付中で、結果公開は2026年9月の予定です。

動的更新の読み上げ設計:ライブリージョンとフォーカス移動の使い分け

画面が書き換わったことは、放っておけばスクリーンリーダーに伝わりません。通知の手段は2つあり、選択を誤ると無音か過剰読みのどちらかになります。

aria-liveのpoliteとassertiveを分ける条件と初期配置の作法

ライブリージョンはaria-liveで作る仕組みです。politeは現在の読み上げが終わってから通知し、assertiveは読み上げを中断して割り込みます。role="status"はpolite相当、role="alert"はassertive相当として扱われます。

割り込みを使うのは、操作を止める必要がある場面だけです。入力エラー、通信断、処理の失敗。件数の更新や保存完了はpoliteで足ります。すべてをassertiveにすると、読んでいる最中に何度も中断が入り、内容が頭に入りません。

実装で外しやすいのは初期配置です。ライブリージョンは、中身が空の状態で最初のHTMLに置いておき、後からテキストだけを差し込みます。通知のたびにリージョンごとDOMへ追加する書き方では、監視が始まる前に挿入が終わってしまい読み上げられません。

検索結果の更新とSPAの画面遷移でフォーカスを移す位置の決め方

更新範囲が大きい場合、ライブリージョンでは伝えきれません。絞り込み結果の総入れ替えや、SPAでの画面遷移がこれにあたります。この場合はフォーカスそのものを移します。

移す先は、更新された領域の見出しです。見出しにtabindex="-1"を付けてスクリプトからフォーカスを当てると、そこから下を読み進められます。ページ全体の先頭に戻すと、毎回ナビゲーションを読み直すことになるため避けます。

件数だけが変わる小さな更新でフォーカスを動かすと、入力中のカーソルが飛んで操作を妨げます。フォーカス移動は「読者の現在地が無効になったとき」に限ってください。

フォームエラーを読み上げに届けるaria-describedbyとrole=alert

フォームのエラーは3つを組み合わせます。エラー文の要素をaria-describedbyで入力欄に紐づけ、当該欄にaria-invalidを立て、送信時のエラー要約をrole="alert"で通知する。この3点で、欄に戻ったときも通知の瞬間も内容が読み上げられます。

色だけでエラーを示す実装は、読み上げにも色覚特性のある利用者にも届きません。文字での説明を必ず添えます。枠線の色そのものの基準値はWebアクセシビリティのコントラスト比:4.5対1と3対1の適用範囲で扱っています。

自動検証で拾えない読み上げ欠陥と、実機検証に回す対象の絞り込み

axeなどの自動検証が判定する範囲と、機械判定に載らない読み上げの欠陥

axeなどの自動検証が確実に拾うのは、名前が空のボタン、参照先が存在しないaria-labelledby、フォーカス可能な要素へのaria-hidden、見出しレベルの飛びといった、構造として矛盾している箇所です。ここは人が聞くまでもありません。

一方、機械が判定できない代表が3つあります。読み上げ順が意味として通っているか。アクセシブルネームが画面に見えている文言と一致しているか。代替テキストが画像の内容を説明しているか。いずれも「文字列が入っているか」は判定できても「内容が正しいか」は判定できない領域です。

この線引きを共有せずに自動検証だけで合格を出すと、違反0件のまま読み上げが破綻したサイトが納品されます。診断そのものを自動・手動・当事者検証の三層で組む考え方はWebアクセシビリティ診断の進め方:自動・手動・当事者検証の三層設計と外注の判断基準で整理しています。

アクセシビリティツリーのスナップショットで順序の回帰を止める

読み上げ順の回帰は、テストで固定できます。PlaywrightのAria Snapshotsは、ページのアクセシビリティツリーをYAML形式で書き出し、期待値との差分を検出します。役割と名前が順番どおりに並んでいるかを、そのままアサーションにできる仕組みです。

これを主要導線のページに入れておくと、CSSの並べ替えやコンポーネント差し替えで順序が崩れた瞬間にCIが落ちます。実機での確認は初回に集中させ、以降の回帰はスナップショットで受ける分担なら運用に耐えます。機能の詳細はPlaywright の Aria Snapshots が提供するアクセシビリティ検証機能とはを参照してください。

実機検証に回す3種類の画面と、自動検証で済ませる画面の線引き

実機で聞くべき画面は3種類に絞れます。第1にカスタムUI部品を含む画面(タブ、コンボボックス、モーダル、ドラッグ操作)。第2に動的更新のある画面(絞り込み、非同期の読み込み、トースト通知)。第3にフォームです。この3つで、読み上げ欠陥の大半が起きます。

逆に、記事本文やお知らせ一覧のような静的ページを1枚ずつ聞くのは工数の無駄です。テンプレートが同一なら代表1枚を実機で確認し、残りは自動検証とツリーのスナップショットで足ります。100ページのサイトで実機検証を10枚に絞る、という配分が現実的な出発点になります。

この絞り込みを設計せずに全ページ実機を掲げた案件は、初回で予算を使い切り、改修後の再検証ができなくなります。改修と再検証の往復まで含めた体制づくりはWebアクセシビリティ対応としてご相談を承っています。

ARIAを足すべき場面と、足さずにネイティブ要素へ戻すべき場面

ネイティブ要素に無いタブやツリーの構造でARIAを足す判断基準

ARIAが必要になるのは、HTMLに対応する要素が存在しないパターンだけです。タブ、ツリービュー、コンボボックス、ツールバー。これらはrole="tablist"のような役割と、キーボード操作の実装をセットで書く必要があります。

実装の型はARIA Authoring Practices Guideに掲載されており、役割の組み合わせと必要なキー操作が明記されています。自分でキーバインドを考えず、この型どおりに実装してください。矢印キーでタブを移動するのか、Tabで移動するのかといった細部が、利用者の期待と一致していないと操作できません。

逆に、開閉パネルはdetails要素、選択肢はselect要素、ダイアログはdialog要素で足ります。ARIAを書く前に、対応するネイティブ要素が無いかを毎回確認する。この習慣だけで属性の量は目に見えて減ります。

divとroleの自作部品を見送り、既存ライブラリへ寄せる条件

Reactなどでカスタム部品を作る場合、キーボード操作・フォーカス管理・役割と状態の同期をすべて自前で書くと、実装量に見合った品質になりません。3人以下のチームで独自のコンボボックスを新規実装する判断は、まず見送るべきです。

採用条件は逆に明確です。デザイン要件がライブラリの構造と衝突する、あるいは既存の部品が保守されていない場合に限って自作へ進みます。それ以外はヘッドレスのアクセシビリティライブラリへ寄せ、検証の対象を自社のマークアップだけに減らすほうが確実です。実装の選択肢はReact Ariaとは?Adobe製アクセシビリティライブラリの構成・使い方で扱っています。

読み上げ検証で繰り返し出る3つの失敗パターンと修正を進める順序

現場で繰り返し出る欠陥は決まっています。1つ目は名前の空白で、アイコンボタンとリンク画像に集中します。2つ目はaria-labelによる表示文言の上書き。3つ目はフォーカス可能な要素の非表示化で、閉じたメニューやカルーセルの画面外スライドに残ります。

  1. 名前が空の要素を自動検証で抽出し、内包テキストまたはラベル要素で名前を与える
  2. 表示テキストを持つ要素のaria-labelを外し、見えている文言と一致させる
  3. タブキーで通し操作し、無音になるフォーカス位置と背景への抜けを塞ぐ

よくある質問

スクリーンリーダー対応の実装と検証について、問い合わせの多い5点をまとめました。

検証はNVDAとJAWSのどちらを使うべきですか?

納品要件で指定が無いならNVDAで始めてください。WebAIMの第10回調査では主に使うスクリーンリーダーがJAWS 40.5%、NVDA 37.7%と拮抗しており、検出できる構造上の欠陥も大きく重なります。NVDAは無償のためチーム全員の端末に入れられます。JAWSは公共調達などで明示的に要求された場合に追加してください。

aria-labelを付ければ読み上げは直りますか?

むしろ悪化する場合があります。aria-labelは要素の内包テキストを上書きするため、画面に見えている文言と読み上げが食い違う結果です。音声入力で操作する人は見えている文字を発話するため、その要素を呼び出せなくなります。使ってよいのはアイコンのみのボタンなど、視覚的なラベルが存在しない要素に限ります。

画像のalt属性には何を書けば読み上げが自然になりますか?

その画像が無かったときに文章として補う必要のある情報を書きます。装飾目的の画像はalt=""として木から外し、読み上げさせません。リンクやボタンの中にある画像は、alt属性がそのままリンクの名前になるため、画像の説明ではなく遷移先を書きます。「画像」「写真」といった語をalt属性に含めるのは不要です。

スクリーンリーダー対応はどこまでやれば適合と言えますか?

WCAG 2.2のレベルAAを目標にする場合、読み上げに関係する達成基準は1.3.1(情報及び関係性)、2.4.6(見出し及びラベル)、4.1.2(名前・役割・値)、2.5.3(ラベル・イン・ネーム)などです。「全画面をスクリーンリーダーで聞く」ではなく、これらの基準を満たしているかで判定します。適合の判断と試験は基準単位で進めてください。

検証にはどのくらいの工数を見ておくべきですか?

ページ数ではなくテンプレート数と部品数で見積もります。静的なテンプレートは自動検証と代表1枚の実機確認で足り、工数の大半はカスタムUI部品・フォーム・動的更新のある画面に集中します。改修後の再検証まで含めて初回の1.5倍程度を確保しておくと、指摘の積み残しが出ません。

関連記事

資料請求

RELATED POSTS 関連記事