2015年3月5日

ウインドウのリサイズ操作が終わった時にだけ処理を実行する


レスポンシブデザインで、PCサイズではメニューを表示し、スマホサイズではアイコン化したい場合


例えばメニューのIDが「menu」で、アイコンのIDが「icon」だった場合、CSSは

#menu {display:block;}
#icon {display:none;}
@media only screen and (max-width:640px) {
#menu {display:none;}
#icon {display:block;}
}

などととします。
そしてアイコンをクリックしたときにメニューを表示するために以下のスクリプトを組み込みます。
(JQueryを使用する前提です)

$(function(){
    $("#icon").click(function(){
        $("#menu").toggle();
    });
});

これでとりあえずは実現できたのですが、ちょっと問題が発生します。
アイコンをクリックした後にウィンドウサイズを変更すると、ウィンドウサイズに連動した表示/非表示が機能しなくなるのです。
これはjavascriptで変更したcssはタグに直接記述したのと同じなので元々のcssより優先されてしまうからです。

問題を解消するためはウィンドウサイズ変更時にjavascriptで追加・変更したcssを削除する必要があります。

$(window).resize(function() {
    $("#menu").css('display','');
});

しかし、これではリサイズ中(ドラッグ中)、処理が非常に短い周期で何回も呼ばれてしまいます。
これでも問題無い場合が多いですが、リサイズ終了を待ってから処理を行った方がスマートです。
実際にはリサイズ終了を認識することはできませんので、リサイズイベントから一定時間後(例では200ミリ秒後)に処理を実行するようにし、リサイズイベントのたびにタイマーをリセットすることで処理を1回で済ませるようにします。

var timer = false;
$(window).resize(function() {
    if (timer !== false) {
        clearTimeout(timer);
    }
    timer = setTimeout(function() {
        $("#menu").css('display','');
    }, 200);
});

もっと良い方法があるとは思いますが、とりあえずこれで目的は達せられました。


*********** 追記 1 ***********

スマホでタッチによるスクロールを行うと出ていたメニューが消えてしまうことがわかりました。
つまりリサイズしなくてもスクロールしただけでresizeイベントが発行されてしまうようです。
要修正です。


*********** 追記 2 ***********

推測ですが、スマホでスクロールするとアドレスバーが消えたりスクロールバーが現れたりする関係で一時的に(微妙に)表示領域が変わり、resizeイベントが発生してしまうのではないかと考えました。
そこで以下のようにスクリプトを修正し、前後の画面幅を比較することにしました。
結果は良好で、今のところ狙い通りに動いています。

var timer = false;
var width = $(window).width();
$(window).resize(function() {
    if (timer !== false) {
        clearTimeout(timer);
    }
    timer = setTimeout(function() {
        if (width !== $(window).width()){
            $("#side").css('display','');
            width = $(window).width();
        }
    }, 200);
});






0 件のコメント:

コメントを投稿