今や定番のドロワーメニューやモーダルメニュー。

実装しているサイトは多いのではないでしょうか

ただ、こういったメニューを取り入れているサイトで気になるのが、
メニューを開いている間、メニュー以外のコンテンツがスクロールしてしまう状態。

特に何も対処していない状態

メニューを開いて、メニューのスクロール領域が終わると、メニューの下にあるコンテンツがスクロールしてしまいます。

メニューを開いている間はメニューを見ているので、
コンテンツがスクロールしてしまうのはやめた方がいいかなと思ってます。

スクロールしてしまうことに気づかず、メニューを閉じたら「あれ?ここどこ?」ってなるのはよくないですよね。
上のデモサイトはメニュー背景が半透明なのでスクロールしてることに気づくかもしれませんが、そうでない場合全く分からないです。

  1. 共通HTML
  2. jQueryでやる方法
  3. CSSでやる方法

共通HTML

HTMLは適当にこんな感じにしてます。

<main>
  <p>text1</p>
  <p>text2</p>
  <p>text3</p>
  <p>text4</p>
  <p>text5</p>
  <p>text6</p>
  <p>text7</p>
  <p>text8</p>
  <p>text9</p>
  <p>text10</p>
</main>
<button class="toggle">メニュー</button>
<nav class="menu">
  <ul>
    <li>navigation1</li>
    <li>navigation2</li>
    <li>navigation3</li>
    <li>navigation4</li>
    <li>navigation5</li>
    <li>navigation6</li>
    <li>navigation7</li>
    <li>navigation8</li>
    <li>navigation9</li>
    <li>navigation10</li>
  </ul>
</nav>

CSSは自由でいいですが、メニューが増えてスクロールさせたい場合は以下を書いてください。

.menu ul {
  width: 100%;
  height: 100%;
  overflow-y: scroll;
  -webkit-overflow-scrolling:touch;
}

jQueryでやる方法

実装サンプル

まずは、CSSで以下を用意しておきます。

.fixed {
  position: fixed;
  width: 100%;
  height: 100%;
}

そして以下をJSファイルに書きます。

$(function(){
  var state = false;
  var scrollpos;
  $('.toggle').on('click', function(){
    if(state == false) {
      scrollpos = $(window).scrollTop();
      $('body').addClass('fixed').css({'top': -scrollpos});
      $('.menu').addClass('open');
      state = true;
    } else {
      $('body').removeClass('fixed').css({'top': 0});
      window.scrollTo( 0 , scrollpos );
      $('.menu').removeClass('open');
      state = false;
    }
  });
});

書き方は都度直してほしいですが、何をやっているかというと、

  1. メニューボタンが押されたら、現在のスクロール値を取得
  2. bodyの高さを画面の高さにし、固定する。
  3. position:fixedをかけるとトップに戻ってしまうので、
    現在のスクロール値のtopを指定する
  4. 閉じる時は、bodyのfixedを解除
  5. 再び元のスクロール位置へ戻す。

文字にするとけっこうありますが、スクロールは一瞬でやってくれるので見た目は何てことないです。

今回bodyタグにしてますが、コンテンツエリアのmainに同じ方法をとっても大丈夫です。

CSSでやる方法

実装サンプル

この方法は少しクセがありますが、使える時もあります。

HTMLはそのままで、CSSに以下を追加します。

main {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  overflow-y: scroll;
  -webkit-overflow-scrolling: touch;
}

これはメインコンテンツを前面に配置して、
overflowで擬似的に画面スクロールするように見せています。

この方法だとbody自体は全くスクロールしないので、
メニューが開いてもメインコンテンツがスクロールすることはありません。

ただしいくつか注意点があります。

  1. iOSでは、ステータスバーをタップした時トップに戻る機能が効かなくなる
    (実際にスクロールしているわけではないので)
  2. iOSの場合「overflow-scrolling」を指定しないと慣性スクロールが無くなってしまう。
    ただし指定すると、スクロールに引っかかりがあるような感じになる場合があります。
  3. Androidだとスクロール領域を超えた時のバウンドがなくなる。

擬似的な画面スクロールなので、スクロールに少し難が出てきてしまいます。

2番目のスクロールの引っかかりの具体例は、
例えば一番下までスクロールする→さらに下にスクロールしようとする→上に戻る
とした時に引っかかる時があります。

ただ、この方法でよかった場合もありました。

固定ヘッダーにフォームがある場合です。

ブログとかであるような固定ヘッダーに検索フォームがある場合、
iOSだとフォーカスした瞬間トップへスクロールしてしまうことがありました。

この場合、擬似的に画面スクロールさせる方法にすると、
画面自体がスクロールしているわけではないので、回避することができました。

CSSでやる方法はオススメはできないですが、場合によっては使えることもあります。

さいごに

いろんなサイトをみているとbodyにoverflow:hiddenをかける方法などもあるみたいで、
他にも方法がありそうなので、こういう方法もあるよというのがあれば教えていただきたいです。

Tweet
このエントリーをはてなブックマークに追加
Pocket