tabIndex と focus を使ったページロード時のスクロール制御

# はじめに

Web ページを構築する際に、ページロード時にスクロールする要素を制御したい場合があります。

例えば、以下のページは `body` の `height` を `200vh` に設定しています。ページロード時に、キーボードの**下矢印キー**を押すと、ページ全体がスクロールします。ページ内に表示されている 3 つの記事のいずれかをスクロールさせる場合、工夫が必要です。

![スクリーンショット 2024-07-17 5.23.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2801269/c324011f-9881-d974-51d1-891ca2ba7c8c.png)

本記事では、`tabIndex` と `focus` を組み合わせて、スクロールする要素を制御する方法を紹介します。

# HTML

HTML ファイルを作成します。3 つの記事の要素を記述します。

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>

  <body>
    <div class="container">
      <div class="outer">
        <div class="inner">
          <h2>Title 1</h2>
          <p>
            Lorem, ipsum dolor sit amet consectetur adipisicing elit. Tempore,
            corrupti nesciunt reiciendis reprehenderit odio quis exercitationem,
            ab harum ut unde maiores dolores a culpa mollitia. Aspernatur aut
            beatae voluptatibus explicabo!
          </p>
          <p>
            Lorem, ipsum dolor sit amet consectetur adipisicing elit. Tempore,
            corrupti nesciunt reiciendis reprehenderit odio quis exercitationem,
            ab harum ut unde maiores dolores a culpa mollitia. Aspernatur aut
            beatae voluptatibus explicabo!
          </p>
        </div>
      </div>

      <div class="outer">
        <div class="inner">
          <h2>Title 2</h2>
          <p>
            Lorem, ipsum dolor sit amet consectetur adipisicing elit. Tempore,
            corrupti nesciunt reiciendis reprehenderit odio quis exercitationem,
            ab harum ut unde maiores dolores a culpa mollitia. Aspernatur aut
            beatae voluptatibus explicabo!
          </p>
          <p>
            Lorem, ipsum dolor sit amet consectetur adipisicing elit. Tempore,
            corrupti nesciunt reiciendis reprehenderit odio quis exercitationem,
            ab harum ut unde maiores dolores a culpa mollitia. Aspernatur aut
            beatae voluptatibus explicabo!
          </p>
        </div>
      </div>
      <div class="outer">
        <div class="inner">
          <h2>Title 3</h2>
          <p>
            Lorem, ipsum dolor sit amet consectetur adipisicing elit. Tempore,
            corrupti nesciunt reiciendis reprehenderit odio quis exercitationem,
            ab harum ut unde maiores dolores a culpa mollitia. Aspernatur aut
            beatae voluptatibus explicabo!
          </p>
          <p>
            Lorem, ipsum dolor sit amet consectetur adipisicing elit. Tempore,
            corrupti nesciunt reiciendis reprehenderit odio quis exercitationem,
            ab harum ut unde maiores dolores a culpa mollitia. Aspernatur aut
            beatae voluptatibus explicabo!
          </p>
        </div>
      </div>
    </div>
  </body>
</html>
```

# CSS

`head` 要素内に `style` を記述します。各記事の `outer` に固定の高さを設定し、`inner` がスクロール可能になるようにスタイルを設定します。

```html
<head>
  <style>
    body {
      height: 200vh;
      background-color: blanchedalmond;
    }
    .container {
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .outer {
      width: 300px;
      height: 300px;
      margin: 10px;
      overflow-y: scroll;
    }
    .inner {
      height: 500px;
      padding: 5px 10px;
      background-color: #333;
      color: #fff;
    }
  </style>
</head>
```

# tabIndex の設定

ページロード時のスクロールできるようにしたい要素に `tabIndex` 属性を追加します。

通常の HTML ではフォーカス可能な要素はリンク(`a` 要素)やフォームコントロール(`input`、`textarea` など)に限られます。しかし、`div` 要素でも`tabIndex` 属性を追加することで、その要素がフォーカス可能になり、JavaScript を使ってフォーカスを設定できるようになります。JavaScript でこの要素を操作するため `id` 属性も追加します。

以下では `Title 2` の記事に `tabIndex` 属性を追加しています。

```diff_html
<div class='outer'>
-   <div class='inner' >
+   <div class='inner' id='focus' tabIndex='0' >
        <h2>Title 2</h2>
        <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Tempore, corrupti nesciunt reiciendis reprehenderit odio quis exercitationem, ab harum ut unde maiores dolores a culpa mollitia. Aspernatur aut beatae voluptatibus explicabo!</p>
        <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Tempore, corrupti nesciunt reiciendis reprehenderit odio quis exercitationem, ab harum ut unde maiores dolores a culpa mollitia. Aspernatur aut beatae voluptatibus explicabo!</p>
    </div>
</div>
```

:::note alert

> 警告: tabindex の値として、0 と -1 のみを使用することをお勧めします。tabindex の値を 0 より大きくしたり、フォーカス可能な HTML 要素の順序を変更できる CSS プロパティ（フレックスアイテムの順序）を使用したりしないようにしましょう。これは、キーボードによるナビゲーションや支援技術を使用している人にとって、ページのコンテンツを操作することが難しくなります。代わりに、論理的な順序で要素を記述してください。
>
> [tabindex - HTML: ハイパーテキストマークアップ言語 | MDN](https://developer.mozilla.org/ja/docs/Web/HTML/Global_attributes/tabindex)
> :::

# JavaScript でフォーカスを設定

`head` 要素内に `script` を記述します。ページロード時に特定の記事にフォーカスを設定するために、JavaScript を使用します。

```html
<body>
  <script>
    document.getElementById("focus").focus();
  </script>
</body>
```

# おわりに

本記事で紹介した方法によって、ユーザーにすぐに見せたいコンテンツを強調することが可能になります。ユーザーの注意を特定の部分に向けたい場合に特に便利です。