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
});

または、イベント プロパティを使用します。

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 に感謝します。