スマフォ タップを高速化しUI UX改善

スマートフォンのClickイベントが、PCに比べると遅い事をご存知でしょうか?
本記事では、Clickの反応が遅い『原因』と『対策』について、ご紹介していきます。

本当に遅いの?

まずは、サンプルをご覧ください!!
高速タップサンプル(チェックボックス)
※サンプルは、スマートフォンでご覧ください。

いかがでしょうか?
比較した際に「通常チェックボックス」の反応の悪さにも驚かされますが、
「高速化対応したチェックボックス」の操作感の良さを感じていただけたと思います!!

なぜ遅いの?

遅い原因。それは、スマートフォン特有の操作方法にあります。

まず、スマートフォンにおける「Click(Tap)」とは、何でしょうか?
簡単に表すと「Touch start」→「Touch end」=「Click」となります。

スマートフォンの操作方法には、単純なクリック操作の他に「ダブルタップ」「ピンチイン、ピンチアウト」などが思い浮かぶと思います。
それら、タッチデバイス特有の操作方法は、「Touch end」後に、『判定』『実行』されています。

つまり、遅延と言っているのは『判定にかかる時間』の事になります。

その中でも、遅延原因となっているのは『ダブルタップ』イベントの『判定』なのです。

ダブルタップの判定って、何してるの?

ダブルタップ、つまり「Tap」→「Tap」の事です。
スマートフォンでは、1度目のタッチ後、『約300ms以内』にタッチすると、「ダブルタップ」と判定されます。

要するに、300ms以内にタッチされなかったら、シングルタップ(Click)と判定されます。

つまりは、「シングルタップ」or「ダブルタップ」判定には『300ms』の『待ち時間(Delay Time)』が必要となり、この「Delay Time」が「Click Event」を遅くしている原因になります。
※一部ブラウザでは、300msのDelay Timeを削除しているものもあります。


以下、高速化手法をご紹介します。

高速化①

「ダブルタップ」に伴う機能は、主に「拡大、縮小」となります。

…お気づきの方もいると思います。
そう!
ダブルタップは拡大縮小のためならば、
「拡大縮小を禁止すれば、タップを高速化出来るのでは?」

<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" />

この方法、有効です!
「一部Androidブラウザ」「chrome」では有効なのですが、「iOS safari」では対応していないようです。。

高速化②

高速化①の方法では、一部端末しか対応できませんでした。。
高速化②では、Clickイベントに変わる処理をJSで実装してみましょう。

※ライブラリもありますが、今回は概念を理解するため、ライブラリは使用せずにご説明します。


サンプルとして、チェックボックスの高速化をご紹介します。
高速タップサンプル(チェックボックス)


$(function () {

    var flgMoving = false;

    // PCでも実行できるように、ディバイスによってイベントを変更
    var evntTouchstart = (document.body.ontouchstart === undefined) ? 'mousedown' : 'touchstart',
        evntTouchend = (document.body.ontouchend === undefined) ? 'mouseup' : 'touchend',
        evntTouchmove = (document.body.ontouchmove === undefined) ? 'mousemove' : 'touchmove';


    /**
     * タップイベント制御処理
     * - イベント状態確認し、ステータスフラグ、処理実行を制御
     * 
     * @param {Object} $trigger - タップ要素
     * 
     */
    var touchFast = function($trigger){

        // [touchstart → touchmove → touchend] タップの処理を実行させない。※画面スクロールなどをした場合
        // [touchstart → touchend] タップの処理を実行する。   

        if(event.type === evntTouchstart){
            flgMoving = false;
        }else if(event.type === evntTouchmove){
            flgMoving = true;
        }else if(event.type === evntTouchend){

            if (!flgMoving){
                //タップで実行したい処理を記述

                //疑似ラベル(チェックボックス)処理実行
                if($trigger.hasClass('jsc-fast-label')){
                    touchLabel($trigger);
                }
            }

            flgMoving = false;
        }

    };


    /**
     * 疑似label処理
     * - DOMオブジェクト対し、クラスの付加を制御
     * - DOMオブジェクト内にあるinput要素に対し、チェック状態の制御
     * 
     * @param {Object} $target - タップ要素
     * 
     */
    var touchLabel = function($target){

        var $inputTarget;

        $target.toggleClass('is-chked');
        $inputTarget = $target.find('input');

        if($target.hasClass('is-chked')){
            $inputTarget.prop("checked", true);
        }else{
            $inputTarget.prop("checked", false);
        }

        $inputTarget.change();
    };


    //イベント

    $('.jsc-fast-touch').on(evntTouchstart, function () {
        touchFast($(this));
    });

    $('.jsc-fast-touch').on(evntTouchend, function () {
        touchFast($(this));
    });

    $('.jsc-fast-touch').on(evntTouchmove, function () {
        touchFast($(this));
    });


    $('input').on('change', function () {
        $(this).parent().toggleClass('chked');
    });

});


【ポイント①】イベント判定

クリック処理を「Touchstart」「Touchend」を使用して、実現します。

  • [touchstart → touchmove → touchend]
    • タップの処理を実行させない。※画面スクロールした場合
  • [touchstart → touchend]
    • タップの処理を実行する。  

【ポイント②】「input type=“checkbox"」を非表示に

ソースを見ていただくとわかるのですが、チェックボックスは画像になっています。
理由は、チェックボックス自体もチェックが付くのに「300ms」必要なので、
表示上は、疑似チェックボックスに変更します。
※現時点では、input要素を「display:none」にした場合も、パタメータは問題なく送信する事ができます。

まとめ

300ms遅延は、ダブルタップの判定のため
クリックイベントをJSで実装する事で、改善する事ができます。
画面内操作に適応すると、ユーザービリティが向上し効果が大きい。
input要素が多い画面ほど、適応すべき!
リンク(画面遷移)にも、適応しましょう!