LoginSignup
56
66

More than 5 years have passed since last update.

ハンバーガーメニューを表示する時、背景を固定する方法

Last updated at Posted at 2018-03-09

やること

あらゆるOSにおいて、スクロールがあるハンバーガーメニューを表示している間、背景のスクロールは動かないようにする。

まえおき

基本的に、スクロールさせるには overflow : scroll;、スクロールをしないようにするにはoverflow: hidden;を使うことが一般的。
アプリケーションのhtmlタグには初期値でoverflow : scroll;がついている。
そのため、わざわざoverflow : scroll;を当てなくてもスクロールできるようになっている。

ちなみに

htmlタグにoverflow: hiddenをつけてみてください。ほとんどの場合、スクロールがを防げます。
このほとんどというのがどういうことか後ほどわかります。

実装前のCSSとJSのコード

ハンバーガーメニューのCSS

.humburger-menu {
  /*スクロールするようにする*/
  overflow: scroll;
  /*ハンバーガーをその場に固定*/
  position: fixed;
  /*上端との距離*/
  top: 0;
  /*高さ画面いっぱい*/
  height: 100%;
  /*滑らかスクロール*/
  -webkit-overflow-scrolling: touch;
}

ハンバーガーメニューを開け閉じするJavaScript

function slideIn(){
  // 見やすくするためにするために変数を作成
  var menu = $('.humburger-menu'), // 開け閉じする要素
    menuBtn = $('.hamburger_button'), // メニューボタン
    body = $(document.body),
    menuWidth = menu.outerWidth();

  // メニューボタンをクリックした時の動き
  menuBtn.on('click', function(){
    // body に open クラスをつけたりはずしたりする( open クラスは空)
    body.toggleClass('open');
    if(body.hasClass('open')){
      // open クラスが body についていたらメニューをスライドインする
      body.animate({'right' : menuWidth }, 200);
      menu.animate({'right' : 0 }, 200);
    } else {
      // open クラスが body についていなかったらスライドアウトする
      menu.animate({'right' : -menuWidth }, 200);
      body.animate({'right' : 0 }, 200);
    }
  });
};

試したこと

1. htmlタグに overflow: hidden; を直接つける

function slideIn(){
  var menu = $('.humburger-menu'),
    menuBtn = $('.hamburger_button'),
    body = $(document.body),
    menuWidth = menu.outerWidth();

  menuBtn.on('click', function(){
    body.toggleClass('open');
    if(body.hasClass('open')){
      body.animate({'right' : menuWidth }, 200);
      menu.animate({'right' : 0 }, 200);
      $('html').css('overflow':'hidden') // 追記
    } else {
      menu.animate({'right' : -menuWidth }, 200);
      body.animate({'right' : 0 }, 200);
      $('html').css('overflow':'scroll') // 追記
    }
  });
};

これでほとんど動きます。
しかし、、iOSで正常に動作しません!!

Android, PC : ハンバーガーメニューをスクロールしても背景は動かない
iOS : ハンバーガーメニューをスクロールすると背景もスクロールされる

というわけで不採用!!

2. htmlタグに overflow: hidden; を含むclassつける

新しいCSS class

.scroll-prevent {
  overflow: hidden;
}
function slideIn(){
  var menu = $('.humburger-menu'),
    menuBtn = $('.hamburger_button'),
    body = $(document.body),
    menuWidth = menu.outerWidth();

  menuBtn.on('click', function(){
    body.toggleClass('open');
    if(body.hasClass('open')){
      body.animate({'right' : menuWidth }, 200);
      menu.animate({'right' : 0 }, 200);
      $('html').addClass('scroll-prevent') // 追記
    } else {
      menu.animate({'right' : -menuWidth }, 200);
      body.animate({'right' : 0 }, 200);
      $('html').removeClass('scroll-prevent') // 追記
    }
  });
};

これは完全にダメ元でやりましたね。
1. の結果と同じです...

3. htmlタグに position: fixed; を含むclassをつける

新しいCSS class

.scroll-prevent {
  /*動き固定*/
  position: fixed;
  /*奥行きを管理*/
  z-index: -1;
  /*下2つで背景を元のサイズのまま表示することができる*/
  width: 100%;
  height: 100%;
}
function slideIn(){
  var menu = $('.humburger-menu'),
    menuBtn = $('.hamburger_button'),
    body = $(document.body),
    menuWidth = menu.outerWidth();

  menuBtn.on('click', function(){
    body.toggleClass('open');
    if(body.hasClass('open')){
      body.animate({'right' : menuWidth }, 200);
      menu.animate({'right' : 0 }, 200);
      $('html').addClass('scroll-prevent') // 追記
    } else {
      menu.animate({'right' : -menuWidth }, 200);
      body.animate({'right' : 0 }, 200);
      $('html').removeClass('scroll-prevent') // 追記
    }
  });
};

できました!!
iOSでも求めていた動作が確認できました!!
ちなみにaddClassremoveClasstoggleClassに省略することができます。
こんな風に

function slideIn(){
  var menu = $('.humburger-menu'),
    menuBtn = $('.hamburger_button'),
    body = $(document.body),
    menuWidth = menu.outerWidth();

  menuBtn.on('click', function(){
    body.toggleClass('open');
    $('html').toggleClass('scroll-prevent') // 追記
    if(body.hasClass('open')){
      body.animate({'right' : menuWidth }, 200);
      menu.animate({'right' : 0 }, 200);
    } else {
      menu.animate({'right' : -menuWidth }, 200);
      body.animate({'right' : 0 }, 200);
    }
  });
};

追記

このままだと、ハンバーガー内のリンク先に飛んだ時に、scroll-preventが居残ってしまい、遷移先の画面のスクロールできないことがわかりました。。。

function slideIn(){
  var menu = $('.humburger-menu'),
    menuBtn = $('.hamburger_button'),
    body = $(document.body),
    menuWidth = menu.outerWidth();

  $('html').removeclass('scroll-prevent') // 追記

  menuBtn.on('click', function(){
    body.toggleClass('open');
    $('html').toggleClass('scroll-prevent')
    if(body.hasClass('open')){
      body.animate({'right' : menuWidth }, 200);
      menu.animate({'right' : 0 }, 200);
    } else {
      menu.animate({'right' : -menuWidth }, 200);
      body.animate({'right' : 0 }, 200);
    }
  });
};

この追記でつけたした

$('html').removeclass('scroll-prevent')

scroll-preventclassをページ遷移時にremoveすることで、初期値に戻し異常なく動くようになりました!

余談

これはハンバーガーだけでなく、モーダルなどでも応用することができそうです。(試してないけど)
デザインなどに応じてCSSの中身を変更することで、柔軟に対応することができると思います。
例えばこんな感じ

.scroll-prevent {
  position: fixed;
  z-index: -1;
  width: 100%;
  height: 100%;
  top: 0; /*追記*/
  right: 0; /*追記*/
}

それでもめんどくさいので、全OSがoverflow: hiddenだけで解決できるようになることを期待して終わります。

56
66
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
56
66