みんなに約束してほしい。落ち着いて聞いてほしいんだ。これは、Webプラットフォームの新機能について伝えるためのものなんだ。この機能は、長らく必要とされていたユースケースを満たすだけでなく、すぐに理解でき、意外と強力な構文で実現されている。それが開発者の猫じゃらしであることは間違いないし、実際に試してみて本当に興奮したことを隠すつもりはない。でもその後、私は自制して、この機能を引き出しにしまって、頭の外に追い出すことにしたんだ。これは、絶対に100パーセント必要で、他の方法では解決できない問題を解決するためのツールなんだ。たとえ「機能の構築に反対する」といった手段まで含めてね。だから、みんな落ち着いていてくれないか? いいね。
新しく登場したariaNotify()メソッドは、Accessible Rich Internet Applications (WAI-ARIA) 1.3 Specificationで定義されており、スクリーンリーダーのナレーションをプログラム的にトリガーする手段を提供する。最初の引数として文字列を受け取り、2番目の引数としてオプションの設定オブジェクトを受け取る:
document.ariaNotify( "Hello, World." );
// 呼び出されると、スクリーンリーダーが「Hello, World.」とナレーションする
このように書くとシンプルな解決策に見えるかもしれないが、歴史的には、ARIAのライブリージョンをやや本来の用途とは異なる使い方でしか解決できなかった問題だった。つまり、ライブリージョンを理解すること、そしてその限界を理解することが、ariaNotifyが何をしてくれるのかを理解する鍵となる。ライブリージョンを使ったことがある人なら、このコードスニペットを見た直後にタブを閉じて、腕を高く掲げて部屋を3周目か4周目で喜びに浸っているかもしれない。ライブリージョンを使ったことがない人には、技術的な言葉で言うと:うわぁ、これはひどい状況だ。
支援技術を使った閲覧環境では、ユーザーの操作に応じてページの一部が変更されたり、何かが非同期で読み込まれてページに追加されたりした場合、ユーザーがその変更されたコンテンツにフォーカスを移動するまで、それらの変更は検出できない。ユーザーは、何かが変更されたことすら知る方法がなく、ましてや何が変更されたのかを知ることはできない。ライブリージョンは、少なくとも設計上はこの問題に対処する:aria-live属性を持つ要素は、その要素内に含まれるマークアップの変更をナレーションするきっかけとなる。マークアップが変更されると、変更されたマークアップが声に出して読み上げられる。aria-liveの値がassertiveの場合、支援技術に「これは緊急で、すぐにナレーションすべきだ」と伝える。aria-liveの値がpoliteの場合、「これは次の自然な機会にナレーションされるべきだ」と伝える。要素にrole="alert"またはrole="status"を使用することは、それぞれaria-live="assertive"およびaria-live="polite"と機能的に同等だ。紙の上ではかなり合理的だよね?
当然のことながら、ナレーションされる情報とその方法を細かく調整する方法が必要だったため、ライブリージョンの動作を決定するいくつかの属性がある:
aria-atomic
true: ライブリージョン内の何かが変更されたときに、ライブリージョン全体の内容をナレーションするfalse(デフォルト): 要素内で変更されたテキストのみを通知する
aria-relevant
text: ライブリージョン内でphrasing content(テキスト、その名の通り)が変更されたときにユーザーに通知するadditions: ライブリージョンにノードが追加されたときにユーザーに通知するremovals: ライブリージョンからノードが削除されたときにユーザーに通知するall: テキストが変更された場合、および/または要素がDOMに追加または削除された場合にユーザーに通知する
理論上はこれで十分だ!問題は解決した、と思えるかもしれない。ところが、実際にライブリージョンを使ってみると、ほとんど何をやってもうまくいかない。実際には、ブラウザと支援技術は 非常に 実装に一貫性がない。特に、ライブリージョン内のネストされたマークアップに関しては、aria-liveを期待どおりに動作させるには、通常、使用すべきセマンティックに意味のあるマークアップをすべて削除する必要がある。支援技術を使った閲覧環境全体で確実に動作させるには、ナレーションがトリガーされた時点でライブリージョンがすでにDOMに意味のある形で存在していなければならない。ライブリージョンをdisplay: noneから切り替えたり、ナレーションするコンテンツと一緒にページに挿入したりすると、コンテンツがナレーションされるのを妨げるタイミングの問題が発生する。ブラウザがライブリージョンを最初に「認識」した時点で、「このコンテナ内で変更されるものは何でもナレーションする」とロックインされるため、初期コンテンツが必ずしも含まれるとは限らない。"assertive"と"polite"の値の動作は、仕様や スクリーンリーダーとブラウザの組み合わせでの実現でも十分に定義されていない。繰り返すが:これらは大混乱だ。
仮にそれらの問題がなかったとしても、ライブリージョンの目的と現代のWebの構築方法の間には根本的なミスマッチがある。先ほど述べたように、ライブリージョンは、マークアップが該当する要素に追加/削除された場合にのみ動作するが、それはページの表示内容の変更を引き起こすほとんどのインタラクションの現実ではない。すでにドキュメント内に存在するが、それ以外は無効なマークアップを表示する場合、ライブリージョンは役に立たない。例えば、displayプロパティとdisplay: noneを切り替える場合などだ。このユースケースは、現在のドキュメントの構造的な変更をその場で行う場合と同等か、それ以上に一般的だ。
これらの制限により、ライブリージョンはほとんど通知APIの代用品としてのみ使用されるようになった。ページの奥深くに1つ以上のaria-live要素を視覚的に非表示にして(display: none経由でアクセシビリティツリーから削除せずに)配置し、必要に応じてナレーションさせたいテキストで更新するのだ。私は実際にこれをやってきたが、ライブリージョンが根本的に一貫性がないため、使い勝手が悪い。挿入されたコンテンツは、支援技術を使ってページをナビゲートするユーザーにも必然的に利用可能になり、元の意味から切り離された状態でドキュメント内に浮かんでいる。後片付けを丁寧に行わないと、コンテキストに関連しないナレーションの潜在的に混乱を招くソースをページに追加することになる。最も重要なのは、新しい見えない懸念事項を追加したことだ。専用のテストとメンテナンスが必要な機能であり、文字通り見えない方法で壊れる可能性があり、迷惑をかけたり、誤解を招いたり、混乱させたり、あるいはそのすべてを引き起こす可能性がある。それがアクセシビリティ作業で起こることだ。孤立した状態で下された迅速かつ簡単な決定は、全体的な体験の文脈の中で予期せぬ結果をもたらす可能性があり、それらの仮定が非常に慎重に、早期かつ頻繁にテストされない限り、それらの結果が何であるかを知ることはできない。
ariaNotifyメソッドは、この種のRube Goldberg式のアクセシビリティ仕掛けに取って代わり、複雑で(不安定な)マークアップを必要とせずに、本物のスクリーンリーダー通知APIを提供する:
document.ariaNotify( "Hello, World." );
ariaNotifyはElementインターフェースまたはDocumentインターフェースのメソッドとして利用可能だ。ここで紹介する例では両者の間に意味のある違いはないが、document.ariaNotify()を呼び出すと、html要素で指定されたlang属性が、通知の言語を推測するために使用されることを知っておく価値がある:
const btn = document.querySelector( "button.announce" );
btn.addEventListener("click", function( e ) {
document.ariaNotify( "Hello, World." );
});
/*
* ボタンをクリックすると、<html>要素で指定された`lang`属性を使用して、
* 「polite」タイミングの「hello, world」のアナウンスが行われる。指定がない場合、
* ブラウザのデフォルト言語が使用される。
/*
一方、要素からariaNotify()を呼び出すと、要素の最も近い祖先のlang属性が、通知の言語を決定するために使用される:
const btn = document.querySelector( "button.announce" );
btn.addEventListener("click", function( e ) {
this.ariaNotify( "Hello, World." );
});
/*
* ボタンをクリックすると、ボタン(または`lang`を持つ最も近い親要素)の
* `lang`属性を使用して発音を決定する「polite」タイミングの「hello, world」の
* アナウンスが行われる。ドキュメント内にない場合(<html>まで含めて)、
* ブラウザのデフォルト言語が使用される。
/*
ariaNotifyは、明示的な優先度レベルを設定できる2番目のパラメータを受け取る:
const btn = document.querySelector( "button.announce" );
btn.addEventListener("click", function( e ){
this.ariaNotify( "Hello, world.", {
priority: "high"
});
});
これらの通知のデフォルトの優先度はpriority: "normal"で、これはaria-live="polite"(またはrole="status")のように動作する。明示的なpriority: "high"を設定すると、aria-live="assertive"(またはrole="alert")のように、現在のナレーションを優先し、潜在的に中断する。
これが現時点でのAPIのすべてだ。マークアップをいじる必要もなく、タイミングを調整する必要もない。ナレーションが必要な場合は、ariaNotifyを呼び出すだけで、それがナレーションされる。今すぐFirefoxで試すことができるが、lang属性はまだ考慮されていないようだ:
JAWS
Polite, button. To activate, press space bar. [spacebar pressed] Space. Hello, World.
Assertive, button. To activate, press space bar. [spacebar pressed] Space. Hello, World.
Educado [pronounced correctly], button. To activate, press space bar. Space. Hola, Mundo [pronounced incorrectly].
NVDA
Polite, button. [spacebar pressed] Hello, World.
Assertive, button. [spacebar pressed] Hello, World.
Educado [pronounced correctly], button. [spacebar pressed] Hola, Mundo [pronounced incorrectly].
VoiceOver
Polite, button. You are currently on a button [spacebar pressed] inside of a frame. To click this button, press Control–Option–Space. To exit this web area, press Control–Option–Shift-Up Arrow. Hello, World.
Assertive, button. You are currently on a button [spacebar pressed] Hello, World.
Educado [pronounced correctly], button. You are currently on a button [spacebar pressed] inside of a frame. To click this button, press Control–Option–Space. To exit this web area, press Control–Option–Shift-Up Arrow. Hola, Mundo [pronounced incorrectly].
かなり良いだろう?ライブリージョンの使い方から解放された大きな改善だ。私自身は、ほとんどariaNotifyを使おうとして、そしてまた、すぐに思いとどまるのを待ちきれないでいる!
なぜ躊躇するのか?アクセシビリティの分野では、ARIAの使い方を学ぶには3つの段階があると言われることがある:
- ARIAを使わない。
- ARIAを使う。
- ARIAを使わない。
W3Cはこれを、より形式的な言葉で表現している。彼らの得意分野だ:
すでに組み込まれたセマンティクスと動作を持つネイティブHTML要素[HTML]または属性を使用できる場合は、要素を再利用してARIAロール、ステート、またはプロパティを追加してアクセシブルにするのではなく、そうしてください。
—Using ARIA: First Rule of ARIA Use
ARIA習熟の第2段階で、私たちはトラブルに巻き込まれる。Webは混沌とした場所だが、支援技術はそれとともに進化し、ユーザーが遭遇する可能性のあるより一般的な問題のいくつかを隠蔽することを学んできた。例えば、クリックされたときに視覚的に非表示のコンテンツを明らかにするh2があるとしよう。その要素は、視覚的にはそのインタラクションが明確になるように提示されているかもしれないが、私たちの介入なしには、スクリーンリーダーを介して閲覧するユーザーにはそれ以外の方法で通知されない可能性がある。これを回避するために、支援技術は、その見出し要素に関連付けられたイベントリスナーがあることを検出すると、ユーザーフォーカスを受け取ったときにその見出し要素を「クリック可能」とナレーションすることができる。これは、要素の目的をユーザーに明示的に通知するほど良いものではないが、私たちがそのインタラクションを明示的にしなくても、実用的だ。
問題は、そのインタラクションをどのように明示的にするかという点にある。ARIAに多少慣れている人なら、「この要素はボタンのように動作するので、ユーザーにそれが何かをすることを知らせるためにrole="button"を付けるべきだ」と考えるかもしれない。その衝動は厳密には間違っていないが、その属性には、意図しない結果が伴う可能性が高い。要素の役割を明示的にすることで、その暗黙の意味を削除することになる。ブラウザと支援技術に対して、はっきりと言うと、これは見出しではないと伝えている。ユーザーがドキュメントのアウトラインによってナビゲートしている場合、この要素はもはやそのナビゲーションの一部ではなく、単純で役立つ迅速な修正のように感じられたものが、意図しない結果をもたらすことになる。ARIAには解釈の余地がない。私たちが言うことが、そのまま実行される。「これをナレーションせよ」と言えば、それがナレーションされる。交渉の余地はない。
そこで、「ナレーションせよと指示したら、ナレーションする」と明確に述べる、非常に使いやすい機能が与えられた場合、私はここで、鋼鉄のような、瞬きもしない視線を向けながら、声に出して「alert()」と言うと想像してほしい。モノスペースフォントで発音できたという事実によって、さらに不気味な想像上のシナリオだ。
window.alert( "Hello world, like it or not." );
ずっと昔のalert()を覚えているだろう?悪名高く、かつ厄介なメソッドだ。業界に新しく入った人なら、幸いなことに、直接知る機会はないかもしれない。ariaNotifyと同様に、それは、ユーザーに情報を即座に提示するための迅速で簡単なAPIだった:

alert()はシンプルで、効果的で、一貫性があり、そして、広く使われていた時代には、信じられないほど迷惑なものだった。ariaNotify()は、同じ力をあなたに委ねる。ただし、今回はARIAの目に見えない、揺るぎない権威に裏打ちされている。ariaNotify()が手元にあれば、「これは混乱を招くかもしれないので、何が起こっているのかを正確にナレーションしよう」というのは、迅速で簡単な決定となり、Webの固有の混沌と不整合にもかかわらず、すでにWebのナビゲーションに熟達したユーザーが、すでに理解しているインタラクションについての講義によって閲覧を中断される可能性がある。
心が正しい場所にある開発者が、ページ上のインタラクションによってコンテンツが明らかになったことをユーザーに知らせるためにariaNotifyを使用する様子を想像するのは難しくない。しかし、文脈上、そのコンテンツを明らかにすることは、関連するイベントリスナーの存在、要素の固有のセマンティクス、またはaria-expanded="false"属性(要素とのインタラクションが関連するコンテンツを明らかにすることを通知するための正しいアプローチ)の存在のおかげで、すでに「クリック可能」とナレーションされている要素とインタラクションすることを意味した可能性が高い。その場合、私たちが行ったことは、ユーザーのページ体験にノイズを追加しただけであり、誰もそれを必要としない。つまり、この文の途中でalert( "There's a new comment on this article!" )が3回目にあなたを中断したり、<button>Navigation</button>にホバーしただけで、スキップできないビデオゲームのチュートリアルのようにalert( "Click here to open the navigation." )を食らったりする様子を想像してみてほしい?うわぁ。私はタブを閉じるだろう。
さらに悪いことに、ナレーションされる指示がインタラクション自体の現実と同期しなくなった場合、専用のスクリーンリーダーテストを欠くQAプロセスでは検出されない目に見えない不整合により、ユーザーは、ただ仕事を片付けて一日を終えようとしているのに、背後のページと自分のスクリーンリーダーとの間の口論に耐えさせられることになる可能性がある。
ARIAは強力なものだ。それは、ページ上の要素間の意味、状態、および関係を、絶対的で鉄壁の事実として定義する能力を私たちに与える。それは、私たちWebを構築する者と、それを使用する者の間のコミュニケーションラインを提供する。そのコミュニケーションラインが、ariaNotify()ほど直接的である場所はない。これは、ユーザーが知っていて信頼しているブラウザと支援技術の声を使って、エンドユーザーに直接話しかけることを効果的に可能にする機能だ。それは、単一のメソッドに結び付けられた大きな責任だ。それは非常に現実的な問題を解決するが、多くの技術と同様に、注意深く使用されない場合、同様に多くの問題を引き起こす可能性がある。
私はariaNotify()に興奮している。控えめで、慎重な方法でだ。それは、長年Web(そして私自身)を悩ませてきたユースケースに対処する方法を、驚くほど簡単な方法でついに与えてくれた。実際、その簡単さゆえに、ariaNotify()は少し危険なものになっている。
つまり、私たちにとってはそうではないよね?なぜなら、私たちは皆、このことについて落ち着いているつもりだからだよね、ね?
ね。
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.