Tabキーによるフォーカス・ナビゲーションについての覚え書き

# 基本用語
- Webブラウザの閲覧時に、`Tab`キーを押して一定の順序でフォーカスを移動させることを「**シーケンシャル・フォーカス・ナビゲーション**」などという。
    - フォーカスしていることを表す青い枠は「**フォーカスリング**」という。

# 基本操作
- `<a>` にフォーカスした状態で、Enterキーを押すと遷移する。
- `<button>` は、Enterキー / Spaceキーで発動する。
- Safari は `Tab`キーのみでは、十分にフォーカス移動できず、ボタンなどがスキップされる。これは Safari の設定をいじることで解決可能である（[参考記事](https://zenn.dev/wozitto/articles/aa71637c484540)）。ウェブサイト開発者の側からどうこうできる問題ではない。
- Mac では、ブラウザ上部に表示される警告ダイアログを、キーボードのみで十分に操作することはできない。これは仕様なので諦めるしかない。
![スクリーンショット 2024-06-05 22.46.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257189/cb881193-aa59-a595-de20-d38f8edcee8e.png)


# HTML・CSSコーディングの注意点

- リセットCSSに下記コードを用意するとよい。
    - 疑似要素 `:focus-visible` にフォーカスリング（青い枠）を設定する。マウス操作でクリックした時にはフォーカスリングが表示されないが、`Tab`キーを使ったときには表示される。
    - `:focus` を使うと、マウス操作のときにもリングが表示され、見映えがよくないので注意。
```scss:reset.scss
input,
textarea,
button,
select {
    &:focus {
        outline: none;
    }
    &:focus-visible {
        outline: -webkit-focus-ring-color auto 1px;
    }
}
```

- チェックボックス・ラジオボタンは**決して　`display: none` / `visibility: hidden` にしてはいけない**。絶対にフォーカスできなくなってしまう。
    - `tabindex` をつければフォーカス出来るようになるが、Enter / Space で選択できないため無意味である。
    - かつては、チェックボックス・ラジオボタンを `display: none` にして、`:before` / `:after` でスタイリングするのが一般的であったが、これは**古い手法**である。最新のCSS仕様では、**チェックボックス・ラジオボタンを直接スタイリングすることが可能**であり、こちらの方が望ましい。（[参考記事](https://www.tak-dcxi.com/article/summary-of-css-techniques-posted-on-x-in-june-2024#%E3%83%A9%E3%82%B8%E3%82%AA%E3%83%9C%E3%82%BF%E3%83%B3%E3%82%84%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%83%9C%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E8%A3%85%E9%A3%BE%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AF-input-%E8%A6%81%E7%B4%A0%E3%81%AB%E7%9B%B4%E6%8E%A5%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AB%E3%82%92%E3%81%82%E3%81%A6%E3%82%8B)）

<br>

- HTMLのインラインイベントハンドラーについて
    - 特別な理由がない限り、**`onmousedown` 属性よりも `onclick` 属性を使うべき**である。
    - `onclick` に設定した内容は、Enterキー / Spaceキー でも発動する。そのため、別途 `onkeydown` などを設定する手間を省くことができる。
    - 逆に、`onmousedown` に設定した内容は、キーボードでは発動しない。
    - そもそも、HTMLのインラインイベントハンドラーを使うべきではないという話もある（[MDN](https://developer.mozilla.org/ja/docs/Learn/JavaScript/Building_blocks/Events#インラインイベントハンドラー_—_使用しないでください)）が、まだまだ案件によっては完全排除は難しいだろう。

<br>

- **アコーディオンは `<details>` と `<summary>` で作ったほうがよい**。
    - [こちらの記事](https://ics.media/entry/220901/)が詳しい。

<br>

- **モーダルは `<dialog>` で作った方がよい**。
    - [こちらの記事](https://www.tak-dcxi.com/article/implementation-example-of-a-modal-created-using-the-dialog-element/)が詳しい。
    - `<dialog>` を使うときは「最上位レイヤー」の概念をよく理解する必要あり。
    - `<dialog>` を使えば　`Tab`キーによるフォーカス・ナビゲーションを簡単に制御することができる。逆に、`<dialog>` を使わないと、ゴチャゴチャした JavaScript コードを自作するなり、ライブラリを組み合わせる必要なりがあって苦行である。
    - まだキッチリと考えきってはいないが、ハンバーガーメニューも `<dialog>` で作った方がよい気がする。テキトーに古い手法で作ると、「閉じた状態のハンバーガーメニューの中のリンクにフォーカスが移動してしまい、ユーザーがフォーカスを見失う」といった事態が発生する。

<br>

- 同じ見た目のボタンを表現するのに **`<a>` と `<button>` が混在**していると、アクセシビリティ上の問題が発生する。
    - `<a>` は、Enter キーを押せば遷移できるが、Space キーを押しても何も起きない（代わりにページがスクロールしてしまう）。一方、`<button>` は、Enter キーでも Space キーでも発動する。
    - 従って、`<a>` を使って「ボタンのようなもの」を実装していると、ユーザーが戸惑う可能性がある。
    - しかし、`<a>` を使って「ボタンのようなもの」を実装したい場面は、実際のところ多い。（例えば「削除」と書いたボタン風`<a>`をクリックさせることで、特定のURLにフォームを送信してデータを更新・削除するなど。）
    - **ではどうすればいいのか？　今の私はまだ結論を出せていない。** もう少し時間をかけて調査・考察する必要がある。
        - パッと思いつく方法1：`<a>` に `onkeydown` などを設定する。Spaceキーが押下されたときに、クリックと同様に扱う JavaScript 関数を用意。
        - ~~パッと思いつく方法2：全部 `<button>` でつくる。`<a>`要素のような動作をさせたいときには `　<button onclick="window.location.href='https://example.com'">ほげほげ</button>` と記載する。~~
        - どちらにしろ直観的な書き方とは言いがたく、余計な一手間が必要である。
        - （追記）`<button>` をリンク代わりに用いると、「ホバーで遷移先が分からない」「Ctrl(Cmd) + 右クリックから別ウィンドウに開けない」といった問題があるらしく、やはり望ましくなさそうである。