トピックを検索
画面に出ても読み上げられないステータスメッセージ
「下書きを保存しました」のトーストが文言と一緒に作られるため、aria-liveを付けても、ブラウザーは読み上げるべき変化に気づきません。
問題
スクリーンリーダーの利用者には、作業が保存されたことも、保存に失敗したことも聞こえません。メッセージが一度も読み上げられないまま表示されるためです。
メモアプリが、入力が止まって少したつと下書きを保存します。保存すると、ページの下に小さなトーストが出て「下書きを保存しました」と表示され、3秒後に消えます。画面が見える人はちらりと見て作業を続けます。スクリーンリーダーの利用者は、一段落入力して手を止めても何も聞こえません。下書きが保存されたのか、タブを閉じてよいのか、保存に失敗したのかが分かりません。ない保存ボタンを探したり、念のため本文を別の場所に写したりします。
開発者はトーストに aria-live="polite" を付けていました。それでも何も読み上げられません。
「下書きを保存しました」はステータスメッセージです。フォーカスを移さずに、利用者の操作の結果を伝えます。達成基準4.1.3は、こうしたメッセージを役割やプロパティによって支援技術に伝え、フォーカスを動かさずに読み上げられるようにすることを求めています。ライブリージョンはそのための仕組みですが、ブラウザーがすでに把握している領域の中の変化しか伝えません。この例では、トーストの要素、文言、aria-live を一度に作ってページに追加しています。ブラウザーから見ると、既存の領域が変わったのではなく、内容ごと新しい領域が現れただけです。多くのスクリーンリーダーは何も読みません。見えるメッセージと、聞こえるメッセージが食い違っています。
トーストはページ全体を見ている人に向けて置かれています。音声で聞いている人や、書いている本文を拡大している人は、見落とします。
10グループ中2グループに影響
スキャンはトーストに aria-live があるのを見て合格にします。領域がメッセージと一緒に生まれたことは分かりません。トーストが出ていないときにページを調べると、領域そのものが見つかりません。AIアシスタントはまさにこの書き方をよくします。属性があり、コードが完成して見えるからです。読み上げさせるためにトーストへフォーカスを移す例もありますが、文の途中で本文からカーソルが抜けてしまいます。入力しながらスクリーンリーダーで聞いて、初めて分かります。
試してみる
メモに入力して手を止め、読み上げを聞いてください。
下の欄に、下書きを保存したときのスクリーンリーダーの読み上げが出ます。「下書きを保存しました」は聞こえますか?
問題あり 直してみませんか?
スクリーンリーダーの読み上げ: (メモに入力して、手を止めてください)
再現デモです。「問題あり」は意図的にアクセシブルでない状態にしています。
修正方法
メッセージより前からページにあるステータス領域の、中身だけを変えます。
- 1ステータス領域やトーストのコンテナーは空のままページと一緒に表示し、中身だけを変える。
- 2通常の知らせにはrole="status"を使い、フォーカスは作業中の位置から動かさない。
- 3保存の失敗も含め、結果を言葉で伝える。
<label for="note">メモ</label><textarea id="note"></textarea>この方法を選ぶ理由:メッセージは対象のそばに出す
領域と文言が一緒に現れ、一緒に消えるため、見ていた領域の中で文言が変わったことにブラウザーは気づきません。メッセージは画面に出ても、読み上げられません。
role="status" の p は最初から空のままHTMLにあるため、文言が変わる時点でブラウザーはこの領域を見ています。スクリーンリーダーは読み上げ中の内容を終えてから「10:42に下書きを保存しました」と読みます。カーソルは本文に残ります。この行は編集欄のすぐ下にあり、画面拡大ソフトの利用者も、画面が見える人も、もともと見ている場所です。時刻があるので、保存が新しいことも分かります。
どちらも、フォーカスを動かさずに「下書きを保存しました」を伝えます。編集欄のそばのステータス行を使ってください。コードの量は同じで、失うものがありません。メッセージが利用者の見ている場所に残り、画面拡大ソフトの利用者が見つける前に消えることもありません。トーストのコンテナーが合うのは、サイトがすでにメッセージをトーストで表示していて、それを変えられない場合です。すべてのトーストが一度に直ります。トーストを使う場合は、読むのに十分な時間を表示し、対応が必要な内容はトーストに入れないでください。
領域を先に用意します。 コンポーネントのフレームワークでは、領域をレイアウトか編集欄のマークアップに置きます。メッセージと一緒に現れる {#if} や条件付きの描画の中には置きません。メッセージと一緒に追加される領域は、書き方が違うだけで同じ失敗です。
隠れた領域は読み上げられません。 display: none、visibility: hidden、aria-hidden="true" の中のライブリージョンは読み上げられません。隠していた領域を文言と一緒に表示すると、新しい領域として扱うブラウザーもあります。ステータス行を見た目だけ隠して読み上げさせたい場合は、display: none ではなく、視覚的に隠すクラスを使います。
役割そのものがライブリージョンです。 role="status" は aria-live="polite" と aria-atomic="true" を含んでいます。役割のない div に aria-live="polite" aria-atomic="true" を付けても同じように動きます。通常の保存に aria-live="assertive" や role="alert" を使わないでください。手を止めるたびに、聞いていた内容が遮られます。
伝えるタイミング。 保存が終わったときに伝えます。キー入力のたびや、数秒ごとの「保存中…」は伝えません。同じ文言を続けて書き込むと、2回目を読まないスクリーンリーダーがあります。「10:42に下書きを保存しました」のように時刻を入れれば文言が変わります。または、書き込む前に領域を空にします。
失敗も言葉で伝えます。 「下書きを保存できませんでした」もステータスメッセージです。ページを離れると作業が失われる場合は、保存が回復するまで編集欄のそばにも表示しておきます。
閉じるボタン。 トーストに閉じるボタンを付けることはできますが、ライブリージョン内のボタンは、メッセージと一緒に読まれることがあります(「下書きを保存しました、閉じる」)。それでも問題はありません。ボタンの名前は短くします。避けるためにトーストへ別のライブリージョンを付けると、「修正前」と同じ失敗に戻ります。ボタンだけに頼らず、読むのに十分な時間がたてばトーストが自然に消えるようにもします。
修正にならないもの。 トーストへフォーカスを移せば読み上げられますが、カーソルが本文から抜け、4.1.3が求める方法でもありません。<output> 要素はstatusの役割を持ちますが、変化の読み上げは明示的な role="status" ほど安定していません。
AI コーディングアシスタントで修正しますか? このガイドを Markdown で取得
修正の確認
マウスを使わない4つの確認
確認方法: スクリーンリーダー、キーボード、ズーム
OS、ブラウザーと支援技術のバージョン、ビルド、実施日、各手順の実際の結果を記録してください。トーストのコンポーネントやページのレイアウトを変更した際は、再度確認します。
制限
ライブリージョンの動きは、スクリーンリーダーやブラウザーによって異なります。特に、移動した領域、非表示の領域、ダイアログ内の領域では差が出ます。このパターンは、一つのページの一種類のメッセージを扱っています。読み込み、検索結果、フォームの結果、緊急のアラートは、それぞれ別のトピックです。利用者が使うスクリーンリーダーで、実際のメッセージを確認してください。
よくある問題を再現した学習用のサンプルです。実在のクライアントの診断結果ではありません。コードは出発点となる実装例のため、実際の製品でも確認してください。ここでは支援技術でのテスト結果は報告していません。
コードを更新しても、使いやすさを保つために
ガイドの内容を、コーディングエージェントやCIで使える開発ルールにまとめます。更新後は、キーボードとスクリーンリーダーで再テストし、問題が再発していないか確認します。