Tabだけで最後まで行ってみる
一言でいうと
キーボードアクセシビリティは機能ではなく順序です。何がフォーカスを受け取るのか、どの順番で回るのか、そして今どこにあるのかが見えるのか。この3つがそろえば、ほとんどは片付きます。
なぜ必要なのか
マウスをどけて、Tabキーだけで自分の画面を5分使ってみると、ほとんど必ず何かが見つかります。フォーカスが突然ページの最下部に飛びます。隠してあるメニューの中に入ってしまい、何度押しても出られません。フォーカスが今どこにあるのか見えません。
こうした問題は、QAでは絶対に見つかりません。QAもマウスで行うからです。そして、ユーザーが報告してくることもありません。使えない画面は、報告の対象ではなく、ただ離れていくものだからです。
キーボードだけを使う人は、思ったより多くいます。手首を痛めた人、スクリーンリーダーのユーザー、震えがあってマウスで狙いを定めにくい人、そして単にTabキーのほうが速い人です。この画面が決済画面なら、その人たちは決済ができません。
どう動くのか: 順次フォーカスの順序
HTML標準のtabindexの節が定めている規則は単純です。
1. tabindex 가 양수인 것들 — 값이 작은 것부터, 같으면 문서 순서
2. 그다음 tabindex="0" 과 기본으로 초점을 받는 요소들 — 문서 순서
a[href]、button、input、select、textarea、summaryは、標準でフォーカスを受け取ります。tabindex="-1"はスクリプトからだけフォーカスを与えられ、Tabキーでは移動しません。
ここで人が最もよくつまずくのが正の値のtabindexです。tabindex="3"は、その要素1つを3番目に移すのではなく、ページ全体を2つのグループに分けます。正の値が付いたものが先にすべて回り、そのあとで残りが回ります。そのため、1か所にtabindex="1"を付けると、その要素がページの最初の項目になります。
順序を変えたいときは、マークアップの順序を変えます。tabindexで動かしません。
CSSで見た目の順序だけを変えること(order、grid-row)も、同じ問題を生みます。目に見える順番とTabキーが回る順番が食い違い、WCAGのFocus Orderが述べる「意味が保たれる順序」が崩れます。
スキップリンク
スクリーンリーダーのユーザーはランドマークを飛ばせますが、キーボードだけを使うユーザーにはできません。メニューが20項目あれば、本文にたどり着くまで、ページごとに20回押すことになります。
そのため、ページの最初の項目として、本文へのリンクを置きます。WCAGのBypass Blocksが求めているのは、これです。
ここには落とし穴が2つあります。
- 最初の項目である必要があります: メニューの後ろにあると、飛ばしたいものはすでに通り過ぎたあとです
- 移動先がフォーカスを受け取れる必要があります:
<main id="main">だけでは、ブラウザーがアドレスだけを変えて、フォーカスはそのままにする場合があります。tabindex="-1"を付けると、スクリプトなしでもフォーカスが付いてきます
ふだんは画面の外に置いておき、フォーカスが来たときだけ見えるようにするのが慣例です。.skip { position: absolute; left: -9999px }と.skip:focus { left: 8px }の2行で足ります。
隠したものは本当に隠れているのか
折りたたんだメニュー、閉じたダイアログ、画面の外へ押しやったパネル。これらがタブ順には残っていることはよくあります。フォーカスは移動するのに画面には何も見えないため、ユーザーはTabキーを押すたびにフォーカスが消えるように感じます。
hidden属性やdisplay: none: フォーカス順から完全に外れますinert: その中のすべてが、フォーカス・クリック・読み上げから外れますaria-hidden="true": 支援技術のツリーからだけ消えます。フォーカスはそのまま移動します
最後のものが、最も悪い組み合わせです。フォーカスは移動するのに、スクリーンリーダーは何も読み上げません。MDNのaria-hiddenのドキュメントも、フォーカスできる要素には使わないよう明記しています。aria-hiddenは、文字で描いたアイコンのように、読み上げる必要がなく、フォーカスも受け取らないものにだけ使います。
フォーカスが見えなければならない
outline: noneは、CSSを学ぶ人が最初に覚える1行であり、アクセシビリティを最も大きく壊す1行でもあります。フォーカスリングを消すと、キーボードユーザーは自分がどこにいるのかわからないままTabキーを押すことになります。
:focus-visibleがこの問題を解決します。マウスでクリックしたときには適用されず、キーボードで来たときだけ適用されます。デザインを損なわずに、必要な人にだけリングを見せられます。
現場での姿
このサービスで実際にあったものを3つ書き留めておきます。
- モーダルを開いたのにフォーカスがモーダルへ移動せず、スクリーンリーダーは相変わらず背後の本文を読み上げていました
- 折りたたんだフィルターパネルが
visibility: hiddenではなく高さ0だったため、中のボタンがタブ順にそのまま残っていました - デザインシステムのボタンコンポーネントが
outline: noneを全体に適用し、代わりのスタイルを与えていなかったため、サイト全体でフォーカスが見えませんでした
3つとも、「マウスをどけてTabキーだけで5分」使えば、その場で見つかります。PRチェックリストにその1行を入れることのほうが、自動ツール10個よりも効果があります。
次のラボですること
コンソール画面を1つ書き、Tabキーを押したときに実際に移動する順番を計算ツールで確認します。スキップリンクを最初の項目に置き、正の値のtabindexをなくし、折りたたんだ領域をタブ順から外し、フォーカスの表示を復活させます。