タブ順序を手で直す
目標
キーボードだけで最後まで使える画面を書きます。ブラウザーはありませんが、Tabキーを押したときにどこへ移動するかは、マークアップだけで計算できます。
なぜ重要なのか
キーボードアクセシビリティは機能ではなく順序です。何がフォーカスを受け取り、どの順番で回り、今どこにあるのかが見えるか。そして、この3つは、マウスで確認すると絶対に見つかりません。QAもマウスで行うため、そのままデプロイされます。
特に、正の値のtabindexは、その要素1つを動かすのではなく、ページを2つのグループに分けます。正の値が付いたものが先にすべて回り、残りがそのあとです。tabindex="1"が1つあるだけで、その要素がページの最初の項目になります。
作るもの
/root/work/kbd/app.htmlの1つだけです。フォーカス表示のルールは、文書内の<style>に書きます。
計算ツール
cd /root/work/kbd
python3 /opt/lab/checks/html-kbd-lab/focus.py app.html
Tab順を番号で出力し、正の値のtabindex、aria-hiddenの中にあるフォーカス要素、まがい物のウィジェット、切れたaria-*の参照を指摘します。
ステップ
- スキップリンクを最初の項目に・
mainにtabindex="-1" - タブ順 = 文書順(正の値のtabindexは禁止)
- まがい物のウィジェットをネイティブ要素に
- 装飾は
aria-hidden、折りたたんだ領域はhidden - 開閉ボタン:
aria-expandedとaria-controls - ダイアログ:
role="dialog"・名前・閉じている間はタブ順から除外 - フォーカス表示:
:focus-visible - 計算ツールの結果を
08-focus.txtに - まとめ →
09-notes.md
参考
- JavaScriptは使いません。このラボが見るのは構造です。
aria-hidden="true"はフォーカスを妨げません。フォーカスは移動するのに何も読み上げられない状態が、最も悪いものです。- 実際の画面では、マウスをどけてTabキーだけで5分使ってみるほうが、自動ツール10個よりも多くの問題を見つけます。
スキップリンクを最初の項目に置く
/root/work/kbd/app.htmlを作成し、<body>の最初のフォーカス要素として、<a href="#main">のスキップリンクを置いてください。移動先の<main id="main">にはtabindex="-1"が必要です。
mkdir -p /root/work/kbdを実行します。メニューの後ろに置くと、飛ばしたいものはすでに通り過ぎたあとです。また、移動先がフォーカスを受け取れない要素だと、ブラウザーはアドレスだけを変えて、フォーカスはそのままにします。tabindex="-1"は、Tabキーでは移動しませんが、リンクからはフォーカスを受け取れるようにします。
タブ順を文書順に合わせる
フォーカスを受け取る要素を6つ以上(リンク3つ以上・ボタン2つ以上)に増やし、正の値のtabindexを1つも使わないでください。すでにフォーカスを受け取る要素にtabindex="0"を付けることも禁止です。
計算ツールが番号を付けて出力します。正の値のtabindexが1つでもあると、それらが先にすべて回り、残りがそのあとになります。順序を変えたいときは、マークアップの順序を変えてください。
まがい物のウィジェットをなくす
button要素を3つ以上置き、すべてにtypeを指定してください。role="button"を付けたdiv、onclickが付いたdiv・span、そしてhref="#"のようにどこにも移動しないリンクがあってはいけません。
roleは名札を変えるだけです。フォーカスも、EnterキーやSpaceキーの処理も付いてきません。また、フォームの中でtypeのないbuttonは送信ボタンになり、押すとページが再読み込みされます。移動するならリンク、何かをするならボタンです。
隠したものが本当に隠れているか
読み上げる必要のない装飾要素にaria-hidden="true"を付け、折りたたんだパネルにはhiddenを指定してください。aria-hiddenの中にフォーカスを受け取る要素があってはいけません。また、折りたたんだパネルの中のボタンは、タブ順から外れている必要があります。
aria-hiddenは、支援技術のツリーからだけ消します。フォーカスはそのまま移動します。フォーカスは移動するのに何も読み上げられない状態が、最も悪いものです。文字で描いたアイコンのように、フォーカスも受け取らず、読み上げる必要もないものにだけ使ってください。
開閉ボタンの状態を伝える
aria-expandedとaria-controlsを持つbuttonを置いてください。aria-controlsは実在するidを指す必要があり、aria-expanded="false"のときは、そのパネルにhiddenが付いている必要があります。
矢印の向きだけを変えると、目で見る人にしか状態が伝わりません。aria-expandedは、「今開いているか」をプログラムに伝えます。状態と画面が食い違うと、どちらかが嘘をつくことになります。
ダイアログに名前を付ける
role="dialog"・aria-modal="true"・aria-labelledbyを持つ確認ウィンドウを作り、その中にボタンを2つ(実行・キャンセル)置いてください。最初はhiddenである必要があり、このウィンドウを開くボタンがaria-controlsで結び付けられている必要があります。
名前がないと、開いても「ダイアログ」とだけ読み上げられます。見出し要素をaria-labelledbyで指してください。また、閉じている間にその中のボタンがタブ順に残っていると、ユーザーは見えない場所へフォーカスを送ってしまいます。
フォーカスを見えるようにする
文書内の<style>に:focus-visibleのルールを書き、見えるoutlineを指定してください。outline: noneでフォーカスリングを消すルールがあってはいけません。また、スキップリンクは、ふだんは画面の外にあり、:focusのときに現れる必要があります。
:focusはマウスクリックでも適用されますが、:focus-visibleはキーボードで来たときだけ適用されます。デザインを損なわずに、必要な人にだけリングを見せられます。outline: noneの1行が、アクセシビリティを最も大きく壊す1行です。
タブ順を残す
focus.pyを実行して、結果を/root/work/kbd/08-focus.txtに残してください。保存された項目数が現在の文書のタブ順と同じで、指摘が0件である必要があります。
python3 /opt/lab/checks/html-kbd-lab/focus.py app.html | tee 08-focus.txtを実行します。番号が画面に見える順番と同じかどうかを、目で追って確認してみてください。それが、人がしなければならない確認です。
何が順序を壊すのか
/root/work/kbd/09-notes.mdに3行以上(120文字以上)書いてください。本文にtabindex、건너뛰기、초점が含まれている必要があります(韓国語で「スキップ」と「フォーカス」を意味する語を含みます)。文書自体も、引き続き指摘が0件である必要があります。
核心は1つです。順序はマークアップが決めます。正の値のtabindexが、その要素1つだけでなくページ全体を壊す理由を、自分の言葉で書いておいてください。