横スクロール（スワイプ）をマウスジェクチャーも含めてなるたけ簡単に作ってみた

ブラウザを上下に移動する縦スクロールは、普通だけれど、横スクロールはどうすれはいいか？
とても簡単でコンテナ（スクロールさせたい部分）に `overflow-x: hidden` というCSSを入れれば簡単にできる。

<p class="codepen" data-height="300" data-default-tab="result" data-slug-hash="YzRRwPB" data-user="mayognaise" 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/mayognaise/pen/YzRRwPB">
  Horizontai scroll</a> by Mayo Tobita (<a href="https://codepen.io/mayognaise">@mayognaise</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

携帯やタブレット、デスクトップのトラックパッド、もしくは横スクロール対応のマウスであればこれは完璧に動きます。

しかし、デスクトップでトラックパッドがない場合や横スクロールが対応していないマウスの場合はどうすれば良いでしょうか。

キーボードの場合、アクセシビリティ用に、コンテナに `tabindex="0"` を加えてください。キーボードのタブキーでコンテナをフォーカスした後、左右のキーボードで移動することができます。

マウスの場合、下についているスクロールバーをドラッグして移動させる方法がひとつありますが、多少やりずらいし、携帯のようにスクリーンをスワイプして移動させたいですよね。

残念ながら現在のところはJavascriptを使用しないといけないのです。
いろいろなＪＳライブラリがありますが、自分でできるだけ簡単に作ってみたい！
ということで、極力コードを少なくして作ってみました！

<p class="codepen" data-height="300" data-default-tab="result" data-slug-hash="eYQPMKW" data-user="mayognaise" 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/mayognaise/pen/eYQPMKW">
  Horizontal scroll with keyboard and mouse gesture including accessibility support</a> by Mayo Tobita (<a href="https://codepen.io/mayognaise">@mayognaise</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

まずは、左右のボタンから。仕組みは簡単で、ボタンを押したら、
右の場合はコンテナの幅分を増やして、左の場合はコンテナの幅分を減らしてスクロールさせる

```js
const container = document.body.querySelector(".container");
const { width } = container.getBoundingClientRect();

// 右
container.scrollLeft += width;

// 左
container.scrollLeft -= width;
```

たったこれだけです。
ここでどうやってスムーズにスクロールしているのか？コンテナに `scroll-behavior: smooth` を入れるだけです。そうすると、スムーズに移動してくれます。

アクセシビリティ用に、[ユーザーが過度なアニメーションを望まない設定をしている場合](https://accessible-usable.net/2021/09/entry_210919.html)は、この設定を無効にするのを忘れないでください。

```css
.container {
  overflow-x: auto;
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion) {
  .container {
    scroll-behavior: auto;
  }
}
```

さて、次にスワイプの設定です。マウスイベントには、`movementX` という、前回からの `x` の値からの差分を教えてくれる便利なプロパティがあります。それを使って、スクロールさせるだけです。

```js
const container = document.body.querySelector(".container");

container.addEventListener("mousemove", (event) => {
  container.scrollLeft -= event.movementX * 10
});
```

実際のコードは、コンテナ内でマウスダウンをしたときや、マウスを離したり等の設定をつける必要があります。
最終的なものはこれです。

```js
const container = document.body.querySelector(".container");
let flag = false;

container.addEventListener("mousedown", () => (flag = true));
container.addEventListener("mouseup", () => (flag = false));
container.addEventListener("mouseleave", () => (flag = false));
container.addEventListener("mousemove", (event) => {
  flag && (container.scrollLeft -= event.movementX * 10);
});
container.addEventListener("wheel", (event) => {
  event.preventDefault();
  container.scrollLeft += (event.deltaX + event.deltaY) * 5;
});
```

もちろん、コードをもっと書けば、もっとなめらかに動くよう設定できますが、これが一番コードが少なくて、スワイプを実現しているのではないでしょうか。

もちろん、もっと簡単にできるなら、是非教えてください！:smiley:

読んでいただいてありがとうございました。

【追加修正】

@akebi_mhからマウスホイールを使っての修正をいただきましたのでコードを変更しました！

```js
container.addEventListener("wheel", (event) => {
  event.preventDefault();
  container.scrollLeft += (event.deltaX + event.deltaY) * 5;
});
```

あと、`scrollLeft`はread-onlyではないので、`scrollTo`を使わずに直接設定しました！

```js
const x = 10;
// container.scrollTo(container.scrollLeft + x, 0);
container.scrollLeft += x;
```

@akebi_mhさんありがとうございます！！！