thumbnail

スクロールスナップ時にスクロール量を取得する方法

CSSでscroll-snap-typeを指定した時、普通の方法ではスクロール量の取得ができません。
そこで今回は、ちょっとした工夫でスクールスナップ時にスクロール量を取得する方法を紹介します。

scroll-snap時にスクロール量を取得する方法

完成形のデモ

デモを用意しました。下にスクロールしてみて下さい。
今回紹介するDの方法でスクロール量が取得できていることが分かります。

なお、各アルファベットの意味は以下の通りです。

デモ中の各アルファベットの説明

  • A. window.screenYを使用
  • B. document.body.scrollTopを使用
  • C. document.documentElement.scrollTopを使用
  • D. getBoundingClientRect().topを使用(今回紹介する方法)
  • E. バブリングフェーズで行った場合、スクロールイベントは発生しない

バブリングフェーズではscrollイベントが発火しません。
scrollイベントと組み合わせる場合はキャプチャリングフェーズで実行するようにして下さい。

スクロール量を取得するコードの例

スクロールコンテナのクラスを”container”とすると、

const firstChildDOM = document.querySelector<HTMLElement>('.container > *:first-child')
const scrollPosition = firstChildDOM!.getBoundingClientRect().top * -1

でスクロール量が取得できます。

厳密には、このコードは「ビューポートとコンテナ最初の子要素の高さ方向のずれの大きさ」を計算しています。

コンテナの最初の子要素とは、例えばHTMLが

<div class="container">
  <section>A</section>
  <section>B</section>
  <section>C</section>
</div>

のとき、セクション Aのことを指します。
つまり、ビューポートとセクションAのY座標のずれの大きさをスクロール量とみなします。
以下、分かりやすさのため最初の子要素=セクションAとして話を進めます。

コードの解説

DOM.getBoundingClientRect().top常にビューポートの最上部から対象のDOMの最上部までの距離を返します。今回はビューポートの最上部からセクションAの最上部の距離を考えれば良いことになります。

スクロール前の段階では
セクションAの最上部のy座標 = ビューポートの最上部のy座標 = 0
となっているはずです。
よって、ビューポート最上部からセクションAの最上部の距離は0となります。

スクロールするとビューポートは下に移動するので、
セクションAの最上部のy座標 < ビューポートの最上部のy座標
となり、セクションAまでの距離が大きくなります。

この大きさをスクロール量とみなすことができます。

ただし、ビューポートはセクションAより下にあるので負の数になります。そこで-1 をかけることにより正の数に変換しています。

scroll-snapでスクロール量が取得できない理由

scroll-snap-typeをスクロールコンテナに指定する時、同時にoverflow-y: scroll;も定義する必要があります。このoverflow-y: scroll;を定義すると、一般的な方法でスクロール量を取得することができません。

スクロールコンテナとは、CSSでscroll-snap-typeプロパティを指定する要素のことです

一般的なスクロール量の取得方法とは、次に挙げるような取得方法のことです。

スクロール量の取得方法

  1. window.scrollY
  2. document.body.scrollTop
  3. document.documentElement.scrollTop

しかしスクロールスナップ時はどれだけスクロールを進めても、上記の方法ではスクロール量が常に0となってしまいます。

まとめ

ポイントは3点です。

  • コンテナの子要素の位置を利用する
  • scrollイベントで使う場合はキャプチャリングフェーズで
  • 絶対位置が欲しい場合は -1 をかける

以上、スクロールスナップ時にスクロール量を取得する方法を紹介しました。