こんにちは、フロントエンドエンジニアの mehm8128 です。
今回は新しく検討されている ARIA Notify API について紹介します。
https://blogs.windows.com/msedgedev/2025/05/05/creating-a-more-accessible-web-with-aria-notify/
ARIA Notify とは、既存の ARIA ライブリージョンにおける問題点を基に検討されている、新しい API です。document.ariaNotify() のように命令的に呼び出すことで、スクリーンリーダーや点字ディスプレイなどの支援技術に情報を伝えることができます。
ただし、既存のライブリージョンを完全に置き換えるものではありません。本来の目的で利用されているライブリージョンはそのままで良く、意図しない用いられ方をしてしまっている部分で、より正確に支援技術に情報を通知するための API となっています。
現在は仕様の議論段階で、最低限の機能が入った API が Edge では 136 以降の Origin Trial もしくは feature flag を有効化した状態、Chrome では 140 以降で feature flag を有効化した状態で利用可能です。
以下が explainer で、本記事ではこれを上から順に追っていきます。
https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/Accessibility/AriaNotify/explainer.md
背景として、ライブリージョンにおける問題点が挙げられています。
ライブリージョンについては以下のページにまとまっています。
https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Guides/Live_regions
aria-live のassertive とpolite の挙動が明確に定義されておらず、スクリーンリーダーによって動作が異なっていた上 2 つは必ずしも DOM に結びつかない通知で、3 つ目は最初に編集したセルの DOM に紐づけた通知がしたい(explainer では「Secondary actions」として紹介されています)という用例です。
前述の背景に対して、新しい命令的な API であるariaNotify が提案されました。これは命令的で、ユーザーが直接通知内容を引数に指定して JavaScript から実行する API なので、DOM の中身から通知内容を計算する必要がなく、前述のような一貫性を欠いた挙動を回避することができます。
この関数はdocument.ariaNotify("text") として呼び出すとドキュメントの lang 属性から言語が推測され、document.querySelector("query").ariaNotify("text") として呼び出すと、querySelector で取得した要素の最も近い祖先の lang 属性から言語が推測されます。
// ドキュメントに関連した通知を送信する例document.ariaNotify("John Doe is connected");// 要素に関連した通知を送信する例document.querySelector("#richEditRegion1").ariaNotify("Selected text glowing blue");priority オプション通知の読み上げ中に新しい通知が送信されたとき、優先順位付けをして通知を保留中キューに追加します。
基本的に優先順位付けはスクリーンリーダーが行いますが、ariaNotify を利用する側で明示的に以下の 2 つから優先度を指定することができます。
high: 通知を高優先度通知キューの末尾に追加normal: 通知を全通知キューの末尾に追加// バックグラウンドタスクのステータスが更新されたことの通知(低~普通優先度)document.ariaNotify("Background task completed",{priority:"normal"});// データが消失した可能性があることを知らせる、高優先度の通知document.ariaNotify("Unable to save changes, lost connection to server",{priority:"high",});これはaria-live 属性と似ていて、priority: "high" がaria-live="assertive" に、priority: "normal" がaria-live="polite" に該当します。
iframe を使う親コンテンツは、iframe 内のドキュメントに対してariaNotify で通知を追加することはできません。しかし、iframe 内のドキュメントが自分自身のコンテンツに対してariaNotify することができます。
それゆえ、iframe 内コンテンツの通知が過剰で禁止したい場合は、親コンテンツが iframe のallow 属性やPermissions-Policy などを用いてオプトアウトすることができます。
ariaNotify によって二重通知や冗長な通知が発生する可能性があります。さらには、Web サイト側が支援技術ユーザーのみ弾くためにariaNotify を(たくさん通知を送信するなどして)悪用する可能性があることが懸念されています。
その対策として、UserActivation が利用できるということが書かれています。
Features gated by user activation - Security に記載のある API は既にこの仕組みを利用して、対策を行っているものです。
現在は提供されていないが、検討中で今後サポートされる可能性のある機能について紹介されています。
braille オプションで、点字ディスプレイに対する通知を別で指定することができます。
例えば商品の評価を表す「星 3 つ」を、点字ディスプレイでより簡潔に表すために、「*」を使って以下のように表現できます。
document.ariaNotify("3 stars",{braille:"***"});これは WAI-ARIA 1.3 から入るaria-braillelabel 属性 と似ています。
また、SSMLオプションで読み上げられ方をより細かく指定できます。
SSML とは Speech Synthesis Markup Language(音声合成マークアップ言語)の略で、「ピッチ、発音、読み上げ速度、音量などのテキスト読み上げの出力属性を微調整するために使用できる XML ベースのマークアップ言語」とのことです。
https://learn.microsoft.com/ja-jp/azure/ai-services/speech-service/speech-synthesis-markup
例えば、「911」を「きゅーひゃくじゅーいち」ではなくて「きゅー、いち、いち」と発音させたい場合に、以下のようにinterpret-as="digits" と指定することで、1 桁ずつ読み上げてくれるそうです。
document.ariaNotify("911",{SSML:'<say-as interpret-as="digits">911'});interrupt オプションこれはpriority と少し似ていてややこしいです。別のテキストの読み上げ中にariaNotify で送信されたテキストがどのように割り込むかを指定するオプションです。priority は保留中キューに入っている他の通知との優先順位を指定しするものだったのですが、今回は読み上げ中に割り込むかどうかなどを指定するものです。
オプションを記載しますが、簡略化すると正確性に欠けてしまうため、ほぼ直訳になっています。また、all とpending の違いは太字の部分です。
noneallpriority・interrupt を持つ通知が読み上げられているときは、その読み上げを直ちに中断するpriority・interrupt を持つ保留中の通知があるときは、それらを全て削除するpriority に応じて通知をキューに追加するpendingpriority・interrupt を持つ通知が読み上げられているときは、その読み上げが終了するまで待つpriority・interrupt を持つ保留中の通知があるときは、それらを全て削除するpriority に応じて通知をキューに追加する「ソース」はおそらくariaNotify を呼ぶときに指定したドキュメントや要素のことです(原文で "source")。
提示されているサンプルコードを見ると分かりやすいので、見ていきます。1%から 100%までの進捗状況が順に読み上げられる例です(おそらくwhile などで回すことが想定されています)。
interrupt: "all" の例です。この場合、前のパーセントの読み上げが終わっていなくても、次の読み上げが始まったら読み上げ中の通知が中断され、新しい読み上げが優先されます。
つまり、進捗状況の進む速度が速い場合、「Progress is 100」以外はほとんど聞こえないことになります。
let percent=0;functionsimulateProgress(){ percent+=1;updateProgressBarVisual(percent);document.querySelector("#progressBar").ariaNotify(`Progress is${currentValue}`,{priority:"normal",interrupt:"all",});}if(percent<100){setTimeout(simulateProgress,100);}interrupt: "pending" の例です。この場合、読み上げ中の通知は全て読み上げられるので、「Progress is 1」は確実に読み上げられます。しかし、次の通知が送信されたタイミングでキューは全て削除されるので、1 の読み上げ中に 2 ~ 4 が送信された場合、2 ~ 3 の通知は削除され、次に読み上げられるのは「Progress is 4」となります。そして、最後は「Progress is 100」が読み上げられます。
let percent=0;functionsimulateProgress(){ percent+=1;updateProgressBarVisual(percent);document.querySelector("#progressBar").ariaNotify(`Progress is${currentValue}`,{priority:"normal",interrupt:"pending",});}if(percent<100){setTimeout(simulateProgress,100);}type オプションまだ謎が多いオプションです。少し前まではnotificationId と呼ばれていたようです。
type というオプション、もしくは第二引数に直接文字列を渡すと、通知に対して追加のコンテキストを付与できます。
例えば以下のサンプルコードだと、"task-progress-started" や"task-progress-finished" で追加のコンテキストを与えています。
document.ariaNotify("Uploading file untitled-1 to the cloud.","task-progress-started");myfile.asyncFileUpload().then(()=>{document.ariaNotify("File untitled-1 uploaded.",{type:"task-progress-finished",});});スクリーンリーダーでは、このコンテキストに対してフィルタリングしたり、優先順位の高い通知のみ通知するといったことができるようになります(既になっているのか、今後そうしたい話なのかは不明です)。
例えば上記の例で「type: "task-progress-finished" の通知は通知しない」のようなフィルタリングが適用できるという話です。
同様にこのtype を用いて、点字で出力する指示や、ビープ音を出力するような指示など、様々なカスタマイズができるとのことです。
これについては、事前にtype のプリセットを定義しておくべきなのかという議論もあるようです。
バッジを受け取った著者にはZennから現金やAmazonギフトカードが還元されます。
