Fly higher! Sky is the limit!

webの現場で働く人のブログ

Smooth Scroll (スムーススクロール)、Androidで重い問題。

あけましておめでとうございます!
一発目の記事です。

ということで本記事のタイトル通り、【Smooth Scroll(スムーススクロール)、 Androidで重い問題】についてみていきたいと思います。
よろしくお願いします。

以下のサイトのソースを基にみていきたいと思います。

techacademy.jp

引用ソース

$(function(){
  $('a[href^="#"]').click(function(){
    var speed = 500;
    var href= $(this).attr("href");
    var target = $(href == "#" || href == "" ? 'html' : href);
    var position = target.offset().top;
    $("html, body").animate({scrollTop:position}, speed, "swing");
    return false;
  });
});

このままだと一部、Androidでスムーズに動かないことがあります。(iPhoneは比較的スムーズ)
例えば、画像リンク→ページ内遷移(スムーススクロール)→ページ下部へみたいな動きのときはもっさり感が半端ない。

原因と解決策

なぜこんなにもっさりしているのか...

それは..

Click イベントを使ってるから!

前も言ったかもしれませんが(言ってないかもしれません)モバイルブラウザにおけるclickイベントってかなり重いです。
理由は、Touchイベント,Mouseイベント,Keyboardイベントなど、これらのイベントをすべてclickイベントでは、網羅してしまっているからです。
結果、処理に時間がかかってしまうんですねー。
逆にアクセシビリティ対応をするのであれば、clickってかなり便利だったりするけど...。
(それぞれの処理に対してハックする必要がないので)

解決策ソース:モバイル向け!

$(function(){
    // イベント登録
    $('a[href^="#"]').on('touchstart touchmove touchend', function(event){
        // タッチスタートでフラグを設定
        if ('touchstart' == event.type){
            $(this).attr('data-touchstarted', '');
            return;
        }
        // タッチムーブが発生したら、フラグを消す。(タップと判定させない為)
        if ('touchmove' == event.type){
            $(this).removeAttr('data-touchstarted');
            return;
        }
        // タッチエンド時にフラグがあれば、タップと判定する。
        if ('undefined' != typeof $(this).attr('data-touchstarted')){
            var speed = 500;
            var href= $(this).attr("href");
            var target = $(href == "#" || href == "" ? 'html' : href);
            var position = target.offset().top - 20;
            $("html, body").animate({scrollTop:position}, speed);
            // フラグを削除
            $(this).removeAttr('data-touchstarted');
            return false;
        }
    });
});

touchstart touchmove touchendをそれぞれバインドさせ、
タッチスタート=タッチエンドの時をユーザーがタップしたと判定させ動かしています。
結構、昔から使っている手法だけど、改めて共有ということで...。

PCに対応させたいときは、UA判定で分けてもいいかもですね。

それでは、この辺で。