【jQuery・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; } }); });
書き方は都度直してほしいですが、何をやっているかというと、
- メニューボタンが押されたら、現在のスクロール値を取得
- bodyの高さを画面の高さにし、固定する。
- position:fixedをかけるとトップに戻ってしまうので、
現在のスクロール値のtopを指定する- 閉じる時は、bodyのfixedを解除
- 再び元のスクロール位置へ戻す。
文字にするとけっこうありますが、スクロールは一瞬でやってくれるので見た目は何てことないです。
今回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自体は全くスクロールしないので、
メニューが開いてもメインコンテンツがスクロールすることはありません。
ただしいくつか注意点があります。
- iOSでは、ステータスバーをタップした時トップに戻る機能が効かなくなる
(実際にスクロールしているわけではないので)- iOSの場合「overflow-scrolling」を指定しないと慣性スクロールが無くなってしまう。
ただし指定すると、スクロールに引っかかりがあるような感じになる場合があります。- Androidだとスクロール領域を超えた時のバウンドがなくなる。
擬似的な画面スクロールなので、スクロールに少し難が出てきてしまいます。
2番目のスクロールの引っかかりの具体例は、
例えば一番下までスクロールする→さらに下にスクロールしようとする→上に戻る
とした時に引っかかる時があります。
ただ、この方法でよかった場合もありました。
固定ヘッダーにフォームがある場合です。
ブログとかであるような固定ヘッダーに検索フォームがある場合、
iOSだとフォーカスした瞬間トップへスクロールしてしまうことがありました。
この場合、擬似的に画面スクロールさせる方法にすると、
画面自体がスクロールしているわけではないので、回避することができました。
CSSでやる方法はオススメはできないですが、場合によっては使えることもあります。
さいごに
いろんなサイトをみているとbodyにoverflow:hiddenをかける方法などもあるみたいで、
他にも方法がありそうなので、こういう方法もあるよというのがあれば教えていただきたいです。