scroll-blockingが発生するイベントリスナーにpassiveを指定してスクロールジャンクを防ぐ方法。

scroll-blocking解決_001

Chromeのデベロッパーツールでサイトを検証すると警告タブに[violation]という違反項目が出ていたので対応しました。

どうやらWordpressで使用しているファイルの一つ「comment-reply.min.js」内のtouchstartイベント内でpassiveが指定されていないため、スクロール反応の邪魔をしています!という旨のようです。

Googleが提供するPageSpeed Insightsで「スクロールパフォーマンスを高める受動的なリスナーが使用されていません」と出る場合の解決策でもあります。

イベントリスナーの第三引数にpassive: trueを追記すれば解決できます。

passiveでスクロールパフォーマンスを高める

touchstartをはじめ、touchmove、wheel、mousewheelなどタッチやスクロールに関するイベントリスナーを登録する時、preventDefault()メソッドを使用していないのであれば、イベントハンドラーを適切に記述することでスクロールパフォーマンスを最適化できるとのことです。

scroll-blocking解決_001

Chromeデベロッパーツールでのwarning

Chromeで出る全文がコチラ。

[Violation] Added non-passive event listener to a scroll-blocking <some> event. Consider marking event handler as 'passive' to make the page more responsive. See <URL>

【Google日本語翻訳】
[違反] スクロールをブロックする<some>イベントに非パッシブイベントリスナーを追加しました。ページの応答性を高めるために、イベントハンドラーを「パッシブ」としてマークすることを検討してください。<URL>を参照

WordPressに含まれる「comment-reply.min.js」内の記述ではイベントハンドラー(第三引数)にpassive:trueが記述されていない為、Chromeでこの警告が出ます。

今回、touchstartイベントに警告が出ています。
スクロールする度にconsoleのメッセージが増え続けて気になるので対処しました。

専門用語ばかりでややこしいですが、詳しく書きますので是非ご確認ください。
プログラムについてそれほど詳しくなくても対処可能ですのでご安心を。

スクロールジャンクについて

割愛しようとも思いましたが、重要な項目なのでこの内容から記述します。
主にモバイル端末でスクロールが遅延する現象をスクロールジャンクと言います。
スクロールしているのにガタついたり、詰まったりするような状態です。

このスクロールジャンクが発生する主な原因はJavascriptの処理待ちです。
PreventDefault()と呼ばれるメソッドを利用すれば、ブラウザの標準動作を防ぐことが出来るのですが、これが問題です。

例えばスクロールに対して何も指定していない場合、そのままスクロールという動作になりますが、PreventDefault()メソッドを使用することでスクロール動作を止めることが出来ます。
(スクロール処理を中断して他の処理をしたい場合などに使用する。)

PreventDefault()が呼ばれた場合にはスクロールを止めなければならない訳ですが、ブラウザではコレが使われているか、使われていないかをチェックしてからでないとスクロールを開始できません。

1.イベントリスナ内にPreventDefault()があるかチェック
2.無いことを確認出来たら通常スクロール開始

この確認中の時間がスクロールブロッキングであり、スクロールジャンクが発生してしまう可能性があるということです。
touchstart、touchmove、wheel、mousewheelなどの処理でこのチェックが必要になります。
いちいちスクロールの前に確認していてはスクロールのパフォーマンス、反応が悪くなってしまうというところが困るわけです。

Passive Event Listenerで対処する

なぜイベントハンドラーにpassiveを使うとスクロールパフォーマンスが高まるのか?
ここまでで予想がつく方もおられるかと思います。

ブラウザがイベントリスナー内にPreventDefault()があるか、ないかを事前に察知できればこの問題が解決できます。

そこで、イベントリスナーの登録時に「passive: true」と指定し、このリスナーの中にPreventDefault()は使っていませんよ!と宣言するわけです。

この宣言をしておくとブラウザはチェック処理を行う前にスクロールを開始できるようになるので、スクロールパフォーマンスが向上するということです。

このオプションを使用するにはaddEventListener()の第三引数に{passive: true}を指定すればOKです。

document.addEventListener('touchstart', handler, {passive: true});

ただ注意点があって、比較的新しくできたオプションなので古いブラウザでは対応していない可能性があります。

ブラウザがpassiveを使えるか検証する

最新ブラウザに対応するだけならイベントリスナーの第三引数に{passive: true}を指定すれば対応できるのですが、古いブラウザにも対応する場合には工夫が必要です。

実はaddEventListenerの第三引数には既に別の値が用意されており、{capture: true}として使用することができます。

passiveオプションに対応したブラウザにはpassive:trueを、未対応のブラウザにはcapture:falseを渡さないと意図しない動作になってしまうことが考えられます。

そこでオプションチェック用のコードを追加し、addEventListener内で使用します。

passive対応確認コード

以下のコードをjsファイルの先頭に記述して使えるようにします。

var supportsPassive=false;try{var opts=Object.defineProperty({},'passive',{get:function(){supportsPassive=true;}});window.addEventListener("testPassive", null, opts);window.removeEventListener("testPassive", null, opts);} catch (e) {}

圧縮(minify)されているので見にくいですが、そのまま実用できます。

コードの使い方

passiveの対応をチェックするコードを追加したら、addEventListenerの第三引数を上記コードを使用するように書いて使います。

addEventListener("touchstart",handler,supportsPassive?{passive:true}:false)

上記のサイトに今回と同じような質問がありました。
2年前から「comment-reply.min.js」内のscroll-blocking問題はあるようで、現在も解決していないようですね…

comment-reply.min.jsを改善する

やっと本題です。。。
もはや何の話をしていたか忘れてしまいそう・w・

WordPressの「comment-reply.min.js」内に出ているtouchstartにpassiveハンドラーを追加してスクロールブロッキングを改善しましょうという話でした。

/wp-includes/js/comment-reply.min.js

を開きます。コアファイルなので自己責任でお願いします。

圧縮化されたjsファイルなので見にくいですが、編集する箇所は2か所です。

新しいブラウザで対応ver

最新のChromeやEdgeに対応するだけなら簡単です。IEには対応できません。
古いブラウザにも対応したいなら後者のやり方で行ってください。

{I.addEventListener("touchstart",l)
.addEventListener("touchstart",a)

をcomment-reply.min.js内から探します。
そして以下のように第三引数に{passive:true}を追加すればOK!

{I.addEventListener("touchstart",l,{passive:true})
.addEventListener("touchstart",a,{passive:true})
scroll-blocking解決_002

こんな感じにコードを追加する

min.jsはとても見にくいですが、頑張ってください!

全ブラウザ対応-チェックコード使用ver

passiveオプションに対応しているかどうかのコードを使った方法です。
若干ややこしくなりますが、こちらの方がオススメです!
編集する箇所は先ほどの2か所で同じです。

まず対応確認するため、下記のコードをcomment-reply.min.jsの先頭に記述する。

var supportsPassive=false;try{var opts=Object.defineProperty({},'passive',{get:function(){supportsPassive=true;}});window.addEventListener("testPassive", null, opts);window.removeEventListener("testPassive", null, opts);} catch (e) {}

ややこしそうなので一応画像も載せておきます。

scroll-blocking解決_003

コードの先頭にチェックコードを追記

続いてtouchstartが使用されている部分を以下のように書き換えます。

{I.addEventListener("touchstart",l,supportsPassive?{passive:true}:false)
.addEventListener("touchstart",a,supportsPassive?{passive:true}:false)
scroll-blocking解決_004

第三引数にチェックコードを追加

こんな感じです。

保存してページを読み込みなおし、Chromeのデベロッパーツールを開いて確認すると、スクロールした時に[violation]の警告が出なくなっているかと思います。

参考

・comment-reply.min.jsですが、コメントへの「返信」を押したときに、返信するコメントの真下にコメントフォームが移動するのに使っているファイルらしいです。あまり使わないのにエラーが出るという…

まとめ

はい、今回も超大作になりました。

PageSpeed Insightsの「スクロールパフォーマンスを高める受動的なリスナーが使用されていません。ページのスクロールパフォーマンスを高めるには、touchおよびwheelイベントリスナーを'passive'として指定することをご検討ください」の意味が分からなかったのですが、ようやく解決に至りました。

どうせなら自分のサイトではエラーも警告も0が気持ちよいものです・w・

と思ったらjQueryにも同じエラーが!!
少し眺めたのですが、comment-replyよりも多くの箇所を編集する必要がありそうなので放置します。。。

やっぱり気になりすぎて対処しました!
別記事:jquery.min.jsの編集の項目へ

WordPress標準のjQueryなのでそのうち対応されるでしょ…comment-replyは少なくとも2年対応されていないようですが。

あ!そうそう!おそらくこのスクロールに関する警告はChromeでしか出ません!
Edgeでは別の警告が凄い出てます...もうWeb上での処理が多すぎて全てのブラウザでエラーと警告を0にするのは無理ですね。ハイ。

-サイト構築
-

© 2021 ソロ学