読者です 読者をやめる 読者になる 読者になる

かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

Google Analyticsのスクリプトがあるとページをリロード直後の.scrollTop()が上手く動作しない?

javascript jQuery Google Analytics

1ページの長いサイトを作っていてページがロードされた時にパラメータに合わせて該当する場所に予めスクロールさせたいと思い下記のようなコードを書いていました。

jQuery(function($) {
  (function(w, d) {
    var hash = w.location.hash;
    var $area; // ロード時に表示させるエリア
    /* hashに該当するエリアを取得する処理 */
    // 表示エリアの位置にスクロールさせておく
    $(w).scrollTop( $area.offset().top );
  })(window, document);
});

新規にページを開いた時などは問題なかったのですが 画面をリロードした時に.scrollTop()で値をセットしてもスクロールが動きませんでした。 画面がレンダリングされていない可能性を考慮して

jQuery(function($) {
  (function(w, d) {
    var $w = $(w);
    var hash = w.location.hash;
    var $area; // ロード時に表示させるエリア
    /* hashに該当するエリアを取得する処理 */
    $w.on('load', function() {
      // 表示エリアの位置にスクロールさせておく
      $w.scrollTop( $area.offset().top );
    });
  })(window, document);
});

とか

jQuery(function($) {
  (function(w, d) {
    var hash = w.location.hash;
    var $area; // ロード時に表示させるエリア
    /* hashに該当するエリアを取得する処理 */
    setTomeout(function() {
      // 表示エリアの位置にスクロールさせておく
      $(w).scrollTop( $area.offset().top );
    }, 100);
  })(window, document);
});

と実行の.scrollTop()を実行するタイミングを遅らせてみたのですが上手く動作したりしなかったりと安定しませんでした。どうやら.scrollTop()は動作しているのですが、その後で元のスクロール位置に戻されているようでした。

試しに.scrollTop()ではなく.animate()を使ってスクロールさせてみました。

jQuery(function($) {
  (function(w, d) {
    var hash = w.location.hash;
    var $area; // ロード時に表示させるエリア
    /* hashに該当するエリアを取得する処理 */
    // 表示エリアの位置にanimateでスクロールさせる
    $('html, body').animate({
      scrollTop: $area.offset().top
    }, ''fast);
  })(window, document);
});

.animate()は問題なく動作しているようでした。

原因がよく解らないのが気持ち悪かったので、使っているライブラリや読み込んでいるscriptを外して行ってみた所、どうやらGoogle Analyticsのscriptが原因のようでした。Google Analyticsのscriptを外すと.scrollTop()で問題なく読み込み時にスクロールさせることができました。

しかしGoogle Analyticsを外すのは現実的ではありません。
Google Analyticsのcompleteイベントが見つからなかったので、.scrollTop()を使う場合はsetTimeoutで長い時間を取って実行を遅らせるしかなさそうです。
.animate()で素早く移動させてしまうのが安全かもしれません。

色々ろ検索していて、下の記事をみつけました。こちらを読む限りGoogle Analyticsスクリプトだげが原因ではないかもしれません、、、ただ僕の環境ではGoogle Analyticsスクリプトを外すと.scrollTop()でも問題なく動作したので謎は深まりますが、こちらの記事でも同様に.animate()を使う結論に至っていたようです。