繰り返すナビゲーションを飛ばせないスキップリンク
スキップリンクを display: none で隠し、本文もただの div に置いているため、メニューを飛ばす手段がありません。
問題
キーボード利用者が、どのページでもメニュー全体をTabで移動しないと本文にたどり着けません。
園芸店のオンラインショップのヘッダーには、ロゴ、12のカテゴリーリンク、検索欄、アカウント、買い物かごが並んでいます。キーボードで「春植え球根」のページを開いてTabキーを押すと、フォーカスはロゴ、各カテゴリー、検索欄、アカウント、買い物かごの順に移動します。最初の商品は17番目です。次のページでも、同じ16か所を先に通ります。
テーマにはスキップリンクがありますが、表示させないために display: none で隠しています。そのためTabの移動先からも外れ、誰も使えません。本文とヘッダーはどちらもただの div で、最初の見出しも p を見出し風にしただけです。スクリーンリーダーで移動できるランドマークや見出しもありません。WCAG 2.4.1は、ページごとに繰り返される部分を飛ばす手段を求めていますが、このページには一つもありません。
一か所ずつ移動するキーボード利用者やスイッチ利用者は、ページを開くたびにヘッダーを通る負担を負います。スイッチ操作では、一か所の移動に数秒かかることもあります。スクリーンリーダー利用者はランドマークや見出しで移動できますが、それはページにあればの話です。画面拡大ソフトの利用者は、横に長いヘッダーをフォーカスが進む間に現在位置を見失います。
自動チェックはHTMLの中にスキップリンクを見つけると、display: none で移動先から外れていても「ある」と判断することがあります。リンク先のidが実在するか、スクロールだけでなくフォーカスも移るかまでは、ほとんど確認しません。生成された修正は <a href="#main"> を追加しても、id="main" を持つ要素を忘れがちです。シングルページアプリケーションでは、ルーターがハッシュリンクを横取りして、動いていたスキップリンクが壊れることもあります。
試してみる
Tabキーで最初の商品まで移動してください。
本文までの移動回数を数えてください。修正後は、最初の移動先でEnterを押してください。
修正方法
スキップリンクをフォーカス時に表示してmain要素に向けるか、ランドマークと見出しでページを構成します。
- 1本文をmain要素に入れ、移動先を用意する。
- 2スキップリンクは最初のTab移動先にし、フォーカス時に表示して、移動先へフォーカスを移す。
- 3スキップリンクは見た目だけ隠し、display: none は使わない。
html
<a class="skip-link" href="#content">Skip to content</a><div class="header"> <a href="/">Fernway Garden</a> <ul class="menu">…12 category links…</ul> <input type="search" aria-label="Search"> <a href="/account">Account</a> <a href="/basket">Basket</a></div><div class="content"> <p class="title">Spring bulbs</p> …</div>css
.skip-link { display: none; }display: none でリンクがTabの移動先から外れ、#content に一致するidもありません。ランドマークも見出しもないため、ヘッダーを飛ばす手段がありません。
リンクは最初のTab移動先になり、フォーカスすると画面に現れます。リンク先が実在し、tabindex="-1" で main がフォーカスを受け取れるため、どのブラウザーでも次のTabはヘッダーに戻らず本文の中から始まります。目で見てキーボード操作する人も、このリンクを見つけて使えます。
どちらも2.4.1を満たします。目で見てキーボードやスイッチで操作する人を助けるのはスキップリンクだけで、必要なのはリンク一つと数行のCSSです。ランドマークと見出しは維持の手間がほとんどなく、すべてのスクリーンリーダー利用者に役立ち、1.3.1も満たしますが、Tabで移動する距離は変わりません。スキップリンクを置き、ランドマークも加えてください。今回のリリースでどちらか一方しかできない場合は、スキップリンクから始めます。
リンクはtransform、clip、画面外への配置で隠し、display: none、visibility: hidden、hidden は使いません。:focus のときは隠す指定を外します。ほかのリンクと同じフォーカス表示を付け、ヘッダーの背景に対して十分なコントラストにします。
main に tabindex="-1" を付けると、ブラウザーによっては本文全体にフォーカスの枠が出ます。移動先が分かるため問題ありません。消す場合も outline: none ではなく main:focus:not(:focus-visible) を使います。tabindex="0" で main を通常のTab移動先にはしません。
固定ヘッダーが、移動後の main の上端を覆うことがあります。移動先にヘッダーの高さ分の scroll-margin-top を指定します。シングルページアプリケーションでは、ルーターが #main へのリンクを横取りしないか確認し、横取りする場合はクリックを処理して移動先の focus() を呼びます。スキップリンクは共通レイアウトに置き、すべてのページにリンクと移動先があるようにします。
ほとんどのサイトでは、本文へのスキップリンクが一つあれば十分です。ほかにも長い繰り返し部分がある場合に限り、「絞り込みを飛ばす」などを追加します。
修正の確認
マウスを使わない5つの確認
確認方法: キーボード、スクリーンリーダー、ズーム
OS、ブラウザーと支援技術のバージョン、ビルド、実施日、各手順の実際の結果を記録してください。ヘッダーやレイアウトを変更した際は、再度確認します。
制限
このサンプルは、どのアプリケーションでも同じ結果になることを保証するものではありません。繰り返し部分が複数あるページ、iframe、アプリの共通画面では、複数の手段が必要になることがあります。実際のページで、操作全体を確認してください。
よくある問題を再現した学習用のサンプルです。実在のクライアントの診断結果ではありません。コードは出発点となる実装例のため、実際の製品でも確認してください。ここでは支援技術でのテスト結果は報告していません。
コードを更新しても、使いやすさを保つために
ガイドの内容を、コーディングエージェントやCIで使える開発ルールにまとめます。更新後は、キーボードとスクリーンリーダーで再テストし、問題が再発していないか確認します。