デフォルトでホイールのスクロールを高速にする

Sahel Sharify
Sahel Sharify

wheel のスクロールとズームのパフォーマンスを向上させるには、{passive: true} オプションを addEventListener() に渡して、wheelmousewheelイベント リスナーをパッシブとして登録することをおすすめします。イベント リスナーをパッシブとして登録すると、ホイール リスナーは preventDefault() を呼び出さず、ブラウザはリスナーをブロックすることなくスクロールとズームを安全に実行できることをブラウザに伝えます。

問題は、多くの場合、wheel イベント リスナーは概念的にパッシブである(preventDefault() を呼び出さない)ものの、明示的に指定されていないため、スクロールやズームを開始するまでブラウザは待機する必要がなくても、JS イベント処理が完了するのを待つ必要があることです。Chrome 56 では、touchstarttouchmove に関するこの問題を修正し、その後、Safari と Firefox の両方にこの変更を採用しました。そのときに作成したデモ動画からわかるように、動作をそのままにしておくと、スクロールの応答に顕著な遅延が発生しました。Chrome 73 では、同じ処理が wheel イベントと mousewheel イベントに適用されています。

介入

この変更の目的は、ユーザーがホイールやタッチパッドでスクロールし始めた後のディスプレイの更新に要する時間を短縮することです。デベロッパーがコードを変更する必要はありません。Google の指標によると、ルート ターゲット(ウィンドウ、ドキュメント、本体)に登録されている wheel および mousewheel イベント リスナーの 75% は、passive オプションの値を指定しておらず、98% を超えるリスナーは preventDefault() を呼び出していません。Chrome 73 では、ルート ターゲット(ウィンドウ、ドキュメント、本文)に登録された wheel リスナーと mousewheel リスナーがデフォルトでパッシブに変更されます。つまり、イベント リスナーには次のような特徴があります。

window.addEventListener("wheel", func);

これは次の式と等しくなります。

window.addEventListener("wheel", func, {passive: true});

リスナー内で preventDefault() を呼び出すと無視され、次の DevTools 警告が表示されます。

[Intervention] Unable to preventDefault inside passive event listener due
to target being treated as passive. See https://www.chromestatus.com/features/6662647093133312

障害とガイダンス

ほとんどの場合、破損はありません。まれに(指標によるとページの 0.3% 未満)、デフォルトでパッシブとして扱われるリスナー内で preventDefault() 呼び出しが無視されるため、意図しないスクロールやズームが発生することがあります。defaultPrevented プロパティを介して preventDefault() の呼び出しが影響しているかどうかをチェックすることで、アプリが実際の環境でこれに該当するかどうかを判断できます。この問題の修正は比較的簡単です。{passive: false}addEventListener() に渡してデフォルトの動作をオーバーライドし、イベント リスナーをブロックとして保持します。