wheel
のスクロール/ズームのパフォーマンスを向上させるには、{passive: true}
オプションを addEventListener()
に渡して、wheel
と mousewheel
のイベント リスナーを非同期として登録することをおすすめします。イベント リスナーをパッシブとして登録すると、ホイール リスナーが preventDefault()
を呼び出さないことがブラウザに通知され、ブラウザはリスナーをブロックすることなく、安全にスクロールとズームを実行できます。
問題は、ほとんどの場合、ホイール イベント リスナーはコンセプト上はパッシブ(preventDefault()
を呼び出さない)であるにもかかわらず、明示的にパッシブとして指定されていないため、ブラウザは JS イベント処理が完了するのを待ってからスクロール/ズームを開始する必要があります。Chrome 56 では、touchstart
と touchmove
に関するこの問題を修正し、この変更は後に Safari と Firefox の両方で採用されました。当時作成したデモ動画でわかるように、この動作をそのままにすると、スクロール レスポンスに顕著な遅延が発生します。Chrome 73 では、wheel
イベントと mousewheel
イベントにも同じ介入を適用しました。
介入
この変更の目的は、ユーザーがホイールまたはタッチパッドでスクロールを開始した後に、デベロッパーがコードを変更することなくディスプレイの更新にかかる時間を短縮することです。Google の指標によると、ルート ターゲット(ウィンドウ、ドキュメント、ボディ)に登録されている wheel
イベント リスナーと mousewheel
イベント リスナーの 75% は、パッシブ オプションの値を指定しておらず、そのようなリスナーの 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
故障とガイダンス
ほとんどの場合、破損は発生しません。デフォルトでパッシブとして扱われるリスナー内で preventDefault()
呼び出しが無視されるため、意図しないスクロールやズームが発生することがあります。これは、Google の指標によると、ページの 0.3% 未満のまれなケースで発生します。アプリは、preventDefault()
の呼び出しが defaultPrevented
プロパティでなんらかの効果をもたらしたかどうかを確認することで、この問題が実際に発生しているかどうかを判断できます。影響を受けるケースの修正は比較的簡単です。{passive: false}
を addEventListener()
に渡してデフォルトの動作をオーバーライドし、イベント リスナーをブロックとして保持します。