マウスを使わずにキーボードだけでサイトを見る人は、Tabキーで操作できる要素を順にたどっていきます。
この順番は画面の見た目ではなくHTMLの並びで決まるため、目で見て問題が無くても、たどると遠回りになっていることがあります。
ここでは、SWELLを使っているサイトでTabキーの移動先を実際に数え、どこに手を入れられるかを整理します。
測定はブラウザーの開発者ツールで実行し、数値はこの記事を書いた時点の実測値です。
Tabキーで移動できる要素を数える
ブラウザーの開発者ツールのコンソールで、次のコードを実行します。
const sel = 'a[href],button:not([disabled]),input:not([disabled]),select,textarea,[tabindex]:not([tabindex="-1"])';
const all = [...document.querySelectorAll(sel)];
const main = document.querySelector('main,#main,.l-mainContent,article');
const firstMain = all.find(e => main && main.contains(e));
console.log({
全部: all.length,
本文の最初までの番号: firstMain ? all.indexOf(firstMain) : -1
});実測したサイトでは、Tabで移動できる要素が112個あり、本文の最初のリンクは51番目でした。
キーボードだけで本文のリンクへ行くには、Tabキーを50回押すことになります。
閉じているメニューの中に入ってしまう
移動の先頭にあったのは、画面に見えていないスマホ用メニューの中のボタンでした。
const first = document.querySelector('a[href],button:not([disabled])');
console.log(first.getAttribute('aria-label') || first.textContent.trim());
let e = first;
while (e && e !== document.body) {
const cs = getComputedStyle(e);
console.log(e.className, cs.visibility, cs.opacity, e.hasAttribute('inert'));
e = e.parentElement;
}実測した結果は次のとおりでした。
メニューを閉じる
c-iconBtn -menuBtn c-plainBtn visible 1 false
p-spMenu__closeBtn visible 1 false
p-spMenu__inner visible 1 false
p-spMenu -right visible 0 false外側のp-spMenuはopacityが0で、画面には出ていません。
一方でvisibilityはvisibleのままで、inert属性も付いていません。
この組み合わせだと、見えていないのにTabキーの順番には残ります。
実測したサイトでは、この見えないメニューの中に15個の要素が入っていました。
| 隠し方 | 画面 | Tabの順番 |
|---|---|---|
| opacity: 0 | 見えない | 残る |
| visibility: hidden | 見えない | 外れる |
| display: none | 見えない | 外れる |
| inert属性 | 見える場合もある | 外れる |
opacityだけで隠している箇所は、キーボードの利用者にとっては存在したままになります。
自分のサイトで確かめる
次のコードで、見えないメニューの中に何個入っているかを数えられます。
const drawer = document.querySelector('.p-spMenu');
const sel = 'a[href],button:not([disabled]),input:not([disabled]),select,textarea,[tabindex]:not([tabindex="-1"])';
console.log({
opacity: drawer ? getComputedStyle(drawer).opacity : null,
中の数: drawer ? drawer.querySelectorAll(sel).length : 0
});opacityが0で、中の数が0より大きければ、この状態に当たります。
スキップリンクがあるかを確かめる
先頭から本文まで離れている場合の対処として、最初のTabで本文へ飛べるリンクを置く方法があります。
表示上は隠しておき、フォーカスが当たったときだけ出す形にすることが多いです。
console.log(
[...document.querySelectorAll('a[href^="#"]')]
.slice(0, 5)
.map(a => a.textContent.trim() + ' → ' + a.getAttribute('href'))
);手元の区画をすべて見たところ、スキップリンクの実体はどこにもありませんでした。
このコードは目次などの内部リンクも拾うため、出てきたものが本文へ飛ぶリンクかどうかは、文字とリンク先を見て確かめます。
フォーカスの位置が見えるかを確かめる
Tabキーでたどれても、いまどこにいるかが見えないと操作できません。
キーボードでTabキーを何回か押し、枠線や色の変化が出るかを目で見ます。
出ていない場合、CSSでoutlineを消している箇所があることが多いです。
/* この書き方は、キーボードの利用者から位置が見えなくなる */
*:focus { outline: none; }マウスのクリック時だけ枠線を消したい場合は、focus-visibleを使うと分けられます。
/* マウス操作では出さず、キーボード操作では出す */
:focus:not(:focus-visible) { outline: none; }
:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }この書き方は、キーボードで操作したときだけ枠線を出す指定になります。
確かめた結果を書き留める
手を入れる前後で比べられるよう、数値を残しておきます。
| 項目 | 確かめ方 | 実測した値 |
|---|---|---|
| Tabで移動できる要素の数 | 上のコード | 112 |
| 本文の最初までのTab回数 | 上のコード | 50 |
| 見えないメニュー内の数 | 上のコード | 15 |
| スキップリンク | aタグの先頭を見る | サイトによって有無が分かれた |
| フォーカスの見え方 | Tabキーを押して目で見る | 目視 |
この5つが揃っていれば、直したあとに同じコードを実行するだけで変化が分かります。
手を入れるときの順番
影響の小さいものから試すと、戻しやすいです。
- フォーカスの枠線が出ているかを確かめ、消えていれば戻す
- スキップリンクが無ければ追加する
- 閉じているメニューをTabの順番から外す
- もう一度同じコードを実行して、数値が変わったかを見る
3番目はテーマの動作に関わるため、本番の前に検証用の環境で試すほうが安全です。
メニューの開閉に合わせてinert属性を付け外しする形にすると、閉じている間だけTabの順番から外せます。
ただしテーマの更新で構造が変わる可能性があるため、更新のたびに同じコードで測り直します。
まとめ
- Tabキーの移動順はHTMLの並びで決まるため、見た目では分からない
- 実測したサイトでは、本文の最初のリンクまでTabキーを50回押す必要があった
- opacityだけで隠した要素は、画面から消えてもTabの順番には残る
- visibility、display、inertのどれかを使うとTabの順番から外せる
- 手を入れる前に、要素の数とTab回数を控えておくと変化が分かる
この記事の測定値は、SWELLを使っているサイトで実行したものです。
テーマの版や子テーマの内容によって数は変わるため、自分のサイトで測り直してください。
inert属性の仕様はMDNのリファレンスにまとまっています。
SWELLのカスタマイズはWAZAのまとめにも置いています。



