memorandum
thinking about creation

jQuery:スマートフォン用の全画面メニューがスクロールしても、ページ全体のスクロール位置を変えない

Entry Date _ 2020.02.28
/
ModifiedDate _ 2020.02.28

バーガーメニューを押すとスマートフォン用のメニューが全画面表示でひらく――というよくある仕様においてしばしば問題となるのは、その間ページ全体をどうしておくかだ。さらに、スマートフォン用のメニューでもスクロールしなければならないとなると、かなりややこしくなる。

普通は、ページ全体を固定(position: fixed;)して、メニューが閉じられたらその指定を削除すればいいだけの話だが、この時ページ全体はスクロール途中であったとしてもウィンドウのトップに戻ってしまうという問題がある。

これを回避するには、ページ全体を固定する前の座標を保存しておいて、またその座標に戻せばいいだけの話だのだが、うまくいかない例(Chrome)に当たったということもあり別の方法を試してみた。

要は、ページ全体(window)は固定などせず、そのままにしておいて、ページ全体がスクロールされたら、そのつど強制的に元の位置に戻してしまえばいいのだ。

jQueryの.scroll()は、ターゲットを指定することによって、それぞれ個別にスクロール・イベントを取得することができる。

下の例だと
$(window).scroll~がページ全体で、
$('nav ul').scroll~がスマートフォン用のスクロール・イベントの発生を取得している。

スマートフォン用メニューが表示されたタイミングで、ページ全体の座標を取得し、スクロールが検知される毎にその座標の位置に戻している。

大切なのは、スマートフォン用メニューが閉じられた際に、スクロール・イベントを削除することだ。これをやらないとページ全体はいつまでも同じ位置に居続けることになる。

// -- scroll_start
var scroll_start = function(){

    // スクロール開始時の位置
    var winPos = $(window).scrollTop();

    // ページ全体のスクロール・イベント
    $(window).scroll(function(){
        console.log('window');
        $(window).scrollTop(winPos);
    });

    // スマートフォン用メニューのスクロール・イベント
    $('nav ul').scroll(function(){
        console.log('nav');
    });
}

// -- scroll_stop
var scroll_stop = function(){
    // ページ全体のスクロール・イベントを削除
    $(window).off('scroll');
}

// -- スマートフォン用メニューの表示/非表示
$('#nav-btn a').click(function(){
    if ($(this).html() == 'OPEN'){

        // -- OPEN
        $('nav').show();
        scroll_start();
        $(this).html('CLOSE');

    }else{

        // -- CLOSE
        $('nav').hide();
        scroll_stop();
        $(this).html('OPEN');

    }
});
詳細はサンプルのソースを参照していただきたい。サンプルのHTMLファイルだけでローカルでも再現できるはずだ。

サンプルを表示する

PCで見るとスクロールバーが二重になって若干不格好だが、スマートフォンではその心配も不要だ。

Category

memorandum index