キーボード操作を補助するスキップリンクを配置しよう

Webページを利用するいくつかの人はキーボードを主な操作手段としています。
キーボードで操作する人は、単なる好みや、他のハードウェアの破損、一時的な身体的な制限、視覚的な障がい等さまざまな背景を持ちます。
そのため、Webページを作成する上で、キーボードだけで操作できるように作ることは非常に重要です。

さて、昨今のWebサイトはヘッダーやサイドバーに関連するページのリンクやメニューボタンが用意されています。そのため、メインコンテンツにフォーカスがたどり着くまでにタブキーを複数回押下する必要があります。

現在この記事を見ている方はフォーカスをQiitaのトップに合わせて、以下のリンクまでフォーカスを移動させてみてください。

[フォーカスを当ててね](qiita.com)

タブキーをかなりの回数押す必要があったのではないでしょうか。
初訪問時ならまだしも、ページ遷移や訪問の度にメインコンテンツまでフォーカスを移動する作業は億劫に感じます(何らかの運動機能による事情がある方にとっては億劫どころではありません)。

それを解決するのが[スキップリンク](https://webaim.org/techniques/skipnav/)です。スキップリンクは開いているページのメインコンテンツへ移動するリンクで、これをページの先頭やその近くに置くことで余計なタブキーの押下を削減できます。

残念ですがスキップリンクをそのまま表示すると、キーボードを利用しないユーザーにとっては不要で、混乱を招いてしまいます。
だからと言って、非表示にするだけでは目の見えているキーボードユーザーにとって、とてもわかりにくいものになります(目の見えていないユーザーはキーボードに合わせてスクリーンリーダを用いているので、読み上げさえしてくれれば表示されているかはそこまで関係ありません)。

そこで、スキップリンクを用意する際は、フォーカスを合わせるまで非表示で、フォーカスを合わせると表示されるようなリンクを作ります。

<p class="codepen" data-height="300" data-default-tab="result" data-slug-hash="VYZLGrK" data-pen-title="Untitled" data-user="kokisakano" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/kokisakano/pen/VYZLGrK">
  Untitled</a> by KokiSakano (<a href="https://codepen.io/kokisakano">@kokisakano</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

上記の例では、最初にフォーカスを当てた時に「メインコンテンツに移動する」が現れて、Enterを押すと`header`のナビゲーションがスキップされて「メインコンテンツ内のリンク」にフォーカスが移動します。

## 実装
上記の実装についての解説です。
まず、準備としてスキップリンクが移動するメインコンテンツにアンカーとして`id`属性を付与します。
```html
...
<main id="main">
...
```
そして、スキップリンクを先頭に用意します。遷移先は先ほど`main`に指定した箇所に遷移するようにします。
```html
<a href="#main" class="skip-link">メインコンテンツに移動する</a>
...
```

スキップリンクの初期表示は[tailwindcssのsr-only](https://tailwindcss.com/docs/screen-readers#screen-reader-only-elements)のcssに倣って以下のように定義しています。
```css
.skip-link {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}
```
そして、フォーカスした時の表示は以下のようにしています。
```css
.skip-link:focus {
  position: unset;
}
```


<p class="codepen" data-height="300" data-default-tab="html" data-slug-hash="VYZLGrK" data-pen-title="Untitled" data-user="kokisakano" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/kokisakano/pen/VYZLGrK">
  Untitled</a> by KokiSakano (<a href="https://codepen.io/kokisakano">@kokisakano</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

<p class="codepen" data-height="300" data-default-tab="css" data-slug-hash="VYZLGrK" data-pen-title="Untitled" data-user="kokisakano" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/kokisakano/pen/VYZLGrK">
  Untitled</a> by KokiSakano (<a href="https://codepen.io/kokisakano">@kokisakano</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>