「保存しました」というトーストを画面の右下に一瞬出す。検索フォームで絞り込むと「該当12件」と件数が変わる。マウスと目で操作している人には当たり前に伝わるこれらの変化が、スクリーンリーダーを使う人にはまったく届いていない——受託で納品したサイトを後からアクセシビリティ診断にかけると、ここで指摘が出ることが少なくありません。見た目の変化は実装したが、その変化を「音声でも伝える」設計が抜けている状態です。
この「動的な変化を支援技術に伝える」ための仕組みが、長らく aria-live 領域でした。しかし aria-live は扱いが繊細で、通知が飛んだり重なったりという問題を抱えています。そこに新しく提案されているのが ariaNotify() という API です。本記事では、aria-live の何がつまずきやすいのか、ariaNotify() が何を変えようとしているのか、そして受託の現場で「今」どう実装すべきかを、制作の立場から整理します。
なぜ「画面の変化」が読み上げられないのか
スクリーンリーダーは、基本的に「フォーカスが当たっている場所」や「読み進めている場所」を読み上げます。フォーカスが動かないまま、画面のどこか別の場所がこっそり書き換わっても、利用者にはそれが聞こえません。トーストや件数表示は、まさにこの「フォーカス外で起きる変化」です。
これを伝えるための仕組みが aria-live 属性です。aria-live="polite" を付けた領域の中身が書き換わると、スクリーンリーダーがその変化を読み上げてくれる、という約束になっています。ところが実装してみると、次のようなつまずきが頻発します。
ひとつは、読み上げが飛ぶこと。aria-live 領域は「ページ読み込み時点で DOM に存在していること」が前提です。後から JavaScript で領域ごと差し込むと、その回の変化は読み上げられないことがあります。
ふたつめは、通知が重なる・順番が保証されないこと。短時間に複数の変化が起きると、前の読み上げが中断されたり、どれが読まれるか予測しにくくなります。
みっつめは、ブラウザとスクリーンリーダーの組み合わせ依存です。同じマークアップでも、読み上げソフトによって挙動が変わり、検証コストが膨らみます。
ariaNotify() が変えようとしていること
CSS-Tricks が「ariaNotify() のセイレーンの歌」と少し皮肉混じりに紹介したとおり、ariaNotify() は「DOM の中身を書き換えて、それが読み上げられることを祈る」という間接的なやり方をやめ、スクリプトから直接『これを今読み上げてほしい』と命じることを目指す API です。
// 構想段階のため API 名・引数は変わる可能性がある
element.ariaNotify("ファイルを保存しました", { priority: "normal" });
考え方の肝は、「読み上げてほしい文字列」と「優先度」を、表示用の DOM とは切り離して渡せる点です。aria-live のように「画面に出すテキスト=読み上げるテキスト」という縛りがなくなり、画面には短いアイコンだけ、読み上げには文脈を補った一文、という分担が素直に書けます。通知の順序や重なりの扱いもブラウザ側が引き受ける方向で議論されています。
ただし——ここが受託では最重要ですが——ariaNotify() はまだ標準化の途上で、対応ブラウザも限定的です。CSS-Tricks のタイトルが「セイレーンの歌」なのは、魅力的だが今すぐ全面的に頼ると危ない、という含みです。今日の本番サイトの実装方針は、これを前提に組む必要があります。
受託で「今」採るべき実装方針
新しい API が魅力的でも、納品物は今のブラウザで確実に動く必要があります。受託で今組むなら、次の順序で考えるのが安全です。
| 状況 | 今の推奨実装 |
|---|---|
| トースト・保存完了などの軽い通知 | 事前に置いた aria-live="polite" 領域に文字を入れる |
| エラー・即時に気づくべき警告 | aria-live="assertive" または role="alert" |
ariaNotify() の利用 | 対応ブラウザでの上乗せ(プログレッシブエンハンスメント)に留める |
つまり、土台は今日確実に動く aria-live で作り、ariaNotify() は「対応していれば、より良く伝わる」上乗せとして使うという構えです。これは新しい CSS 機能をフォールバック前提で採用するのと同じ発想で、モダンCSSネイティブ機能をBaselineで採否判断する記事で扱った線引きが、JavaScript の API にもそのまま当てはまります。
aria-live を確実に効かせるコツは、領域をページ読み込み時から空のまま置いておき、後から中身だけ入れることです。
<!-- ページ読み込み時から存在させておく(中身は空) -->
<div id="status" aria-live="polite" class="sr-only"></div>
// 変化が起きたら、領域の「中身」だけを更新する
document.getElementById("status").textContent = "ファイルを保存しました";
受託で見落としがちだった実例
弊社がリニューアルを引き継いだある会員制サービスのサイト(社名は伏せます)では、ログイン後のマイページで操作するたびに右下にトーストが出る作りでした。視覚的には親切な設計でしたが、トーストは操作のたびに JavaScript で <div> ごと新規生成して差し込む実装になっており、スクリーンリーダーでは「保存しました」も「エラーが発生しました」も一切読み上げられていませんでした。エラー通知すら届かないのは、会員サービスとしては看過できない欠落です。
私たちは、トーストの表示ロジックはそのままに、ページ内に空の aria-live="assertive" 領域を一つ常設し、トースト表示と同時にその領域へ同じ文言を流す形へ変えました。やったのは「見えている通知と同じ言葉を、常設の領域にも書き込む」だけです。これで主要なスクリーンリーダーで通知が読み上げられるようになり、エラー時にも音声で気づける状態になりました。フォーム周りの支援技術対応については、認知的インクルージョンとアクセシブルなフォーム設計の記事で扱った観点と合わせると、入力から結果通知までを一貫して伝えられます。
どこから着手するか
まず、いまのサイトで「画面は変わるがフォーカスは動かない」箇所を洗い出すのが出発点です。トースト、件数更新、自動保存の表示、非同期で差し替わるエラーメッセージ——これらはすべて、支援技術には聞こえていない可能性があります。常設の aria-live 領域を一つ用意し、視覚的な通知と同じ言葉をそこへ流すだけで、多くのケースは今日のブラウザで改善できます。ariaNotify() は、その土台ができたうえで「対応ブラウザにさらに良い体験を上乗せする」次の一手として考えれば十分です。
動的な通知が支援技術に届いていない、アクセシビリティ診断で aria-live 周りの指摘を受けた、新しい API を本番にどこまで入れてよいか判断したい——そうしたお悩みがあれば、グリームハブのお問い合わせからご相談ください。現行サイトの動的通知を拝見し、今日確実に動く土台と、将来に向けた上乗せを切り分けて実装します。