課題: 今日の DHTML パッケージはキーボードアクセシビリティが欠けている
増加傾向にあるウェブアプリケーションは、JavaScript を使用してメニューやツリービュー、リッチテキストフィールド、タブパネルなどのようなデスクトップウィジェットを模倣しています。Web 開発者は絶えず表計算やカレンダー、構造図などのような対話的な要素を取り入れ、新たなアプリケーションは複雑化しています。現在まで、Web 開発者はスタイル付けられた <div>
や <span>
を基にして、正しい技術を欠いたウィジェットをキーボードで利用できるようにしようとしています。しかしながら、キーボードアクセシビリティは Web 開発者が知っておくべき最小限必要なアクセシビリティの一部でしかありません。
実例を挙げると、ほとんどの DHTML メニューは、キーボードアクセスを尊重した正規のメニューのようには動作しません。キーボードでとにかくメニューを利用できるようにする場合によくある共通の間違いは、各メニュー項目(<a>
要素を使用して作られます) をタブ移動の順番に含めてしまうことです。実際のメニューの正しい振る舞いは、一度でメニュー全体にタブ移動でき、矢印キーによる操作でメニュー項目からメニュー項目へと移動できるようになっていなければなりません。これはツリービューやグリッド、タブパネルなど、その他の "グループ化された操作" にも当てはまります。
HTML 作者にとっては今すぐできる正しいことです。これらのウィジェットを支援技術との互換性を持たせるためのドキュメントは、ARIA: Accessible Rich Internet Applications 以下にあります。
解決法: tabindex の振る舞いを標準準拠にする
Firefox 1.5 は、Microsoft Internet Explorer が先導する tabindex
属性を拡張することにより、どの要素でもフォーカスできるように変更しています。MSDN: IE システムの <code>tabindex</code> によれば、私たちは、すでに IE でキーボード操作できるようになっているDHTML ウィジェットを Firefox 1.5 でもキーボードで操作できるようにしています。作者がカスタムウィジェットをキーボードで操作できるようにする手段をもつために、ルールは曲げられるべきです。
続く表は、新しい tabindex
の振る舞いについて記述しています:
tabindex 属性 |
マウスまたは element.focus() を用いた JavaScript でフォーカス |
タブ操作 |
---|---|---|
なし | 既定の要素の振る舞いに従う。(フォームコントロールやリンクなどについては可) | 既定の要素の振る舞いに従う。 |
負の値 (例: tabindex="-1" ) |
可 | 不可。作者は矢印キーか他のキーの押下によって element.focus() でフォーカスしなければいけません。 |
0 (例: tabindex="0" ) |
可 | タブで移動する順番は、要素のドキュメント内の位置によります。 |
正の値 (例: tabindex="33" ) |
可 | tabindex の値は、要素の位置にタブで移動する順番を手動で変更します。これらの要素へ移動する順番は、tabindex="0" を持つ要素か、そのままタブで移動できる要素の前に位置します。 |
新しいシステムの使い方
タブで操作できる簡単なウィジェットを作成するには、tabindex="0"
を <div>
または <span>
上に使用してください。span を基にしたチェックボックス の例は Firefox 1.5 と IE の両方で、キーボードで利用できます。(ただし、チェックボックス画像の :before
ルールは IE で動作しません)
メニューやタブパネル、グリッド、ツリービューなど、ウィジェットの集まりの親要素は tabindex="0"
を持つべきです。また、選択肢/タブ/セル/行の子孫要素は tabindex="-1"
を持つべきです。element.focus()
を使用して矢印キーを観察する onkeydown
イベントは、適切な子孫ウィジェットにフォーカスをセットして呼び出すことができるため、フォーカスすることができます。DHTML ツリービュー の例は Firefox の nightly ビルド上で、キーボードとスクリーンリーダで利用できます。(IE 上でも動作します)
これはまだ W3C やその他の公式な標準の一部ではありません。しかし今は、完全にキーボードで利用できるようにするためにルールを曲げる必要があります。
作成時のヒント
onfocus
を使用して現在のフォーカスを追跡する
onfocus
イベントおよび onblur
イベントは、すべての要素で使用することができます。現在のドキュメントのフォーカスを得るための 標準的な DOM インタフェースが無いため、これを追跡し続けるには JavaScript の変数を使用します。
すべてのフォーカス変更はキーイベントとマウスイベントによってのみ起こるとは仮定しないでください。スクリーンリーダなどの支援技術はフォーカスを任意のフォーカス可能な要素にセットすることができ、それらが JavaScript ウィジェットによって的確に扱われる必要があります。
tabIndex
プロパティを使用してフォーカス可能性を動的に変更する
カスタムコントロールが無効なった場合にはフォーカスできなくし、有効になった場合にはフォーカスできるようにしたいはずです。無効になったコントロールにタブで移動するべきではありません。しかしながら、それらが操作ウィジェットの集まりの一部である場合はタブで移動できるようにします。
element.focus()
と setTimeout
を使用してフォーカスをセットする
要素にフォーカスを移すために createEvent()
および initEvent()
, dispatchEvent()
を使用してはいけません。DOM フォーカスイベントは、何かがフォーカスされた後にシステムによって発生しますが、フォーカスのセットには使用されません。タイムアウトは、ユーザがボタンやその他のコントロールをクリックして予期しない動作を起こすスクリプトを防ぐために、IE と Firefox 1.5 の両方で必要です。要素をフォーカスする実際のコードは以下のようになります:
window.setTimeout(function () { focusItem.focus(); },0); // focusItem はスコープ内になければいけません
フォーカスのスタイル付けに :focus
または属性セレクタを使用してはいけません
IE でフォーカスが表れるようにしたい場合、フォーカスのスタイル付けに :focus
または属性セレクタを使用することはできません。onfocus
イベントハンドラ内でスタイルをセットしてください。例えば、<div>
メニュー項目のフォーカスハンドラに this.style.backgroundColor = "gray";
を追加します。
プログラム的にフォーカスを受けた tabindex="-1"
項目および要素にはいつもフォーカスを描く
IE はプログラム的にフォーカスを受けた項目には自動的にフォーカスの輪郭を描きません。this.style.backgroundColor = "gray";
のようにして背景色を変更するか、this.style.border = "1px dotted invert"
のように点線の境界線を追加するか、どちらかを選んでください。点線の境界線にする場合は、はじめに見えない 1px の境界線を要素に指定しておく必要があります。こうしておけば、境界線のスタイルが適用されたときに要素がずれることはありません。(境界線が空白をつくり、IE は CSS の輪郭を提供しません)
キーイベントの追跡には onkeypress
ではなくonkeydown
を使用する
IE は英数字以外のキーで keypress
イベントを発生させることができません。
ブラウザの機能を実行するキーイベントの使用を避ける
矢印キーが使用される場合は、以下のようなコードで、キーを使用をする何か(スクロールなど) からブラウザを避けてください:
<span tabindex="-1" onkeydown="return handleKeyDown();">
handleKeyDown()
が false
を返す場合は、イベントは消費され、キー入力して実行する動作からブラウザを避けます。
キーイベントハンドラを使用して要素のアクティベーションを有効にする
すべてのマウスイベントハンドラには、キーボードイベントハンドラが必要です。例えば、onclick="doSomething()"
には、この要素を Enter キーでアクティベートできるようにするために、onkeydown="return event.keyCode != 13 || doSomething();"
が必要です。
try/catch を使用して JavaScript エラーを回避する
このシステムは現在、Opera および Safari、その他の Mozilla (1.7 およびそれ以前) の古いバージョンではサポートしていません。一部のブラウザは、すべての要素上のtabIndex
プロパティのような新しい能力をサポートしていないため、適切な場所で try/catch を使用してください。DTHML によるキー操作システムをサポートしていないブラウザ上では、ウィジェットをマウスで利用できるようにしておくべきです。このシステムは Opera と Safari でのサポートが WHATWG 仕様を通して計画されています。
キーリピートの振る舞いは一貫していません
困ったことに、onkeydown
が繰り返されるかどうかは、あなたの起動している OS に依存します。Bugzilla データベースの バグ 91592 をご覧ください。