Scrollend(新しい JavaScript イベント)

タイムアウト関数を削除してバグを振り払いましょう。本当に必要なイベントは scrollend です。

Adam Argyle
Adam Argyle

scrollend イベントの登場以前は、スクロールが完了したことを検出する信頼できる方法がありませんでした。そのため、イベントは遅れて発生するか、ユーザーの指が画面に触れている間に発生していました。スクロールが実際に終了したタイミングを正確に把握できないため、バグが発生し、ユーザー エクスペリエンスが低下していました。

document.onscroll = event => {
  clearTimeout(window.scrollEndTimer)
  window.scrollEndTimer = setTimeout(callback, 100)
}

この setTimeout() 戦略でできることは、100ms のスクロールが停止したかどうかを把握することだけです。これにより、スクロールが終了したイベントではなく、スクロールが一時停止したイベントになります。

scrollend イベントの後、ブラウザがこれらの難しい評価をすべて行います。

変更後
document.onscrollend = event => {…}

それが大事なポイントです。タイミングが完璧で、意味のある条件が満たされた後に出力されます。

対応ブラウザ

  • Chrome: 114。
  • Edge: 114.
  • Firefox: 109.
  • Safari: サポートされていません。

ソース

試してみる

イベントの詳細

scrollend イベントは、次の場合に発生します。 - ブラウザでスクロールのアニメーション化または変換が停止した。- ユーザーがタップ操作を解除した。- ユーザーのポインタがスクロール サムから離れた。- ユーザーのキー入力が解除された。- フラグメントまでスクロールが完了しました。- スクロール スナップが完了しました。- scrollTo() が完了しました。- ユーザーがビジュアル ビューポートをスクロールした。

scrollend イベントは、次の場合に発生しません。 - ユーザーのジェスチャーによってスクロール位置が変更されなかった(変換が発生しなかった)。- scrollTo() では翻訳されませんでした。

このイベントがウェブ プラットフォームに導入されるまでに時間がかかったのは、仕様を詳細に定める必要のある細かい点が多かったためです。最も複雑な領域の 1 つは、ドキュメントとビジュアル ビューポートscrollend の詳細を明確にすることでした。ズームインしたウェブページについて考えてみましょう。このズーム状態のときにスクロールできますが、必ずしもドキュメントをスクロールしているわけではありません。この視覚的なビューポートのユーザー主導のスクロール操作でも、完了すると scrollend イベントが送信されます。

イベントの使用

他のスクロール イベントと同様に、リスナーはいくつかの方法で登録できます。

addEventListener("scrollend", (event) => {
  // scroll ended
});

aScrollingElement.addEventListener("scrollend", (event) => {
  // scroll ended
});

または、event プロパティを使用します。

document.onscrollend = (event) => {
  // scroll ended
};

aScrollingElement.onscrollend = (event) => {
  // scroll ended
};

ポリフィルとプログレッシブ エンハンスメント

新しいイベントをすぐに使用したい場合は、次の最善のアドバイスを参考にしてください。現在のスクロール終了戦略(ある場合)を引き続き使用し、その先頭で次のコマンドを使用してサポートを確認できます。

'onscrollend' in window
// true, if available

ブラウザがイベントを提供しているかどうかに応じて、true または false が報告されます。このチェックにより、コードを分岐できます。

if ('onscrollend' in window) {
  document.onscrollend = callback
}
else {
  document.onscroll = event => {
    clearTimeout(window.scrollEndTimer)
    window.scrollEndTimer = setTimeout(callback, 100)
  }
}

scrollend イベントが利用可能になったら、段階的に拡張していくのに適したスタートです。ブラウザで可能な限り最適な動作を実現する、私が作成した ポリフィルNPM)を試すこともできます。

import {scrollend} from "scrollyfills"

// then use scrollend as if it's existed this whole time
document.onscrollend = callback

ポリフィルは、ブラウザに組み込まれている scrollend イベントが使用可能な場合は、段階的に強化されます。利用できない場合は、スクリプトはポインタ イベントを監視し、スクロールしてイベントの終了をできるだけ正確に推定します。

ユースケース

スクロール中に計算負荷の高い処理を実行しないことをおすすめします。この方法により、スクロールは可能な限り多くのメモリと処理を使用できるため、スムーズなエクスペリエンスを維持できます。scrollend イベントを使用すると、スクロールが停止するため、呼び出しを行って負荷の高い処理を行うのに最適なタイミングになります。

scrollend イベントは、さまざまなアクションをトリガーするために使用できます。一般的なユースケースは、関連する UI 要素をスクロールが停止した位置と同期することです。たとえば、カルーセルのスクロール位置をドット インジケータと同期する。- ギャラリー アイテムとそのメタデータを同期する。- ユーザーが新しいタブにスクロールした後にデータを取得する。

ユーザーがメールをスワイプするようなシナリオを想像してみてください。スワイプが完了したら、スクロールした場所に基づいてアクションを実行できます。

このイベントは、プログラムによるスクロールやユーザーによるスクロール後の同期、アナリティクスのロギングなどのアクションにも使用できます。

矢印、ドット、フォーカスなど、複数の要素をスクロール位置に基づいて更新する必要がある例を次に示します。YouTube でこのカルーセルを作成する方法を動画で確認する。また、ライブデモをお試しください

この機能のエンジニアリング作業を担当した Mehdi Kazemi 氏と、API と実装に関するガイダンスを担当した Robert Flack 氏に感謝いたします。