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

Sahel Sharify
Sahel Sharify

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

問題は、ほとんどの場合、ホイール イベント リスナーは概念的にはパッシブ(preventDefault() を呼び出さない)ですが、明示的にそう指定されていないため、ブラウザは JS イベント処理が完了するのを待ってからスクロール/ズームを開始する必要があります。Chrome 56 では、touchstarttouchmove に関するこの問題を修正しました。この変更は、後に 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() に渡してデフォルトの動作をオーバーライドし、イベント リスナーをブロックとして保持します。