タイムアウト関数を削除してバグを振り払いましょう。本当に必要なイベントは scrollend です。
scrollend
イベントが発生する前は、スクロールが完了したことを信頼できる方法で検出できませんでした。そのため、イベントは遅れて発生するか、ユーザーの指が画面に触れている間に発生していました。スクロールが実際に終了したタイミングを正確に把握できないため、バグが発生し、ユーザー エクスペリエンスが低下していました。
document.onscroll = event => { clearTimeout(window.scrollEndTimer) window.scrollEndTimer = setTimeout(callback, 100) }
この setTimeout()
戦略でできることは、100ms
のスクロールが停止したかどうかを把握することだけです。これにより、スクロールが終了したイベントではなく、スクロールが一時停止したイベントになります。
scrollend
イベントの後、ブラウザがこれらの難しい評価をすべて行います。
document.onscrollend = event => {…}
それが大事なポイントです。タイミングが完璧で、意味のある条件が満たされた後に出力されます。
試してみる
イベントの詳細
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 に感謝します。