タイムアウト関数を削除してバグを取り除きましょう。必要なイベントは scrollend です。
scrollend イベントの前は、スクロールが完了したことを確実に検出する方法がありませんでした。つまり、イベントは遅れて発生するか、ユーザーの指が画面に触れている間に発生していました。スクロールが実際に終了したタイミングを把握できないため、バグが発生し、ユーザー エクスペリエンスが低下していました。
document.onscroll = event => { clearTimeout(window.scrollEndTimer) window.scrollEndTimer = setTimeout(callback, 100) }
この setTimeout() 戦略でできるのは、100ms のスクロールが停止したかどうかを把握することだけです。これにより、スクロール終了イベントではなく、スクロール一時停止イベントのようになります。
scrollend イベントの後、ブラウザがこの難しい評価をすべて行ってくれます。
document.onscrollend = event => {…}
それが良いことです。タイミングが完璧で、意味のある条件が満載の状態でエミットされます。
試してみる
イベントの詳細
scrollend イベントは、次の条件を満たす場合に発生します。
- ブラウザがスクロールのアニメーションや変換を停止した。- ユーザーのタッチが離された。
- ユーザーのポインタがスクロール サムを離した。
- ユーザーのキープレスがリリースされた。
- フラグメントへのスクロールが完了しました。
- スクロール スナップが完了しました。
- scrollTo() が完了しました。- ユーザーがビジュアル ビューポートをスクロールした。
次の場合、scrollend イベントは発生しません。
- ユーザーのジェスチャーによってスクロール位置が変更されなかった(変換が発生しなかった)。- scrollTo() で翻訳が行われなかった。
このイベントがウェブ プラットフォームに登場するまでに時間がかかった理由の 1 つは、仕様の詳細が必要な小さな詳細が多数あったためです。最も複雑な領域の 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 イベントが利用可能になったときに、そのイベントを段階的に強化するための健全なスタートとなります。ブラウザで可能な限り最善の処理を行う polyfill(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 に感謝します。