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

# やること
あらゆるOSにおいて、スクロールがあるハンバーガーメニューを表示している間、背景のスクロールは動かないようにする。
# まえおき
基本的に、スクロールさせるには `overflow : scroll;`、スクロールをしないようにするには`overflow: hidden;`を使うことが一般的。
アプリケーションの`html`タグには初期値で`overflow : scroll;`がついている。
そのため、わざわざ`overflow : scroll;`を当てなくてもスクロールできるようになっている。
###ちなみに
`html`タグに`overflow: hidden`をつけてみてください。**ほとんど**の場合、スクロールがを防げます。
この**ほとんど**というのがどういうことか後ほどわかります。
#実装前のCSSとJSのコード
##ハンバーガーメニューのCSS
```css
.humburger-menu {
  /*スクロールするようにする*/
  overflow: scroll;
  /*ハンバーガーをその場に固定*/
  position: fixed;
  /*上端との距離*/
  top: 0;
  /*高さ画面いっぱい*/
  height: 100%;
  /*滑らかスクロール*/
  -webkit-overflow-scrolling: touch;
}
```
##ハンバーガーメニューを開け閉じするJavaScript
```js
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; を直接つける
```js
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`

```css
.scroll-prevent {
  overflow: hidden;
}
```

```js
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`

```css
.scroll-prevent {
  /*動き固定*/
  position: fixed;
  /*奥行きを管理*/
  z-index: -1;
  /*下2つで背景を元のサイズのまま表示することができる*/
  width: 100%;
  height: 100%;
}
```

```js
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でも求めていた動作が確認できました！！
ちなみに`addClass`と`removeClass`は`toggleClass`に省略することができます。
こんな風に

```js
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`が居残ってしまい、遷移先の画面のスクロールできないことがわかりました。。。

```js
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);
    }
  });
};
```

この追記でつけたした

```js
$('html').removeclass('scroll-prevent')
```
で`scroll-prevent`classをページ遷移時にremoveすることで、初期値に戻し異常なく動くようになりました！

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

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

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