iOSでモーダルやハンバーガーメニューを開いている時に、スクロールで背景のコンテンツがスクロールされないようにする方法を調べたのでメモ。
うまくいかなかった例
今回は簡単なモーダルを実装してみます。
HTML
<header class="header">ヘッダー</header> <div class="contents"> <p>コンテンツ本文コンテンツ本文コンテンツ本文コンテンツ本文</p> <p>コンテンツ本文<button class="modal-link" data-modaibody="modal01">モーダル01</button>コンテンツ本文コンテンツ本文コンテンツ本文</p> ~略~ <p>コンテンツ本文コンテンツ本文コンテンツ本文コンテンツ本文</p> </div> <footer class="footer">フッター</footer> <div class="modal-bg"></div> <div class="modal-contents"> <button class="modal-close">閉じる</button> <div class="modal-scroll"> <div id="modal01" class="modal-body"> <p>モーダル01の中身です。</p> </div> <div id="modal02" class="modal-body"> <p>モーダル02の中身です。</p> ~略~ <p>モーダル02の中身です。</p> </div> </div> </div>
.modal-contentsがモーダル部分で.modal-bodyがモーダルの各中身、.modal-scrollで中身が長い時にスクロールできるようにしています。
CSS
html.is-fixed, html.is-fixed body { overflow: hidden; } .modal-bg { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.4); } .modal-bg.is-show { display: block; } .modal-contents { display: none; position: fixed; top: 50%; left: 50%; width: 300px; height: 300px; transform: translate(-50%, -50%); background: #ffffff; } .modal-contents.is-show { display: block; } .modal-scroll { height: 100%; overflow-y: auto; -webkit-overflow-scrolling: touch; overflow-scrolling: touch; } .modal-body { display: none; } .modal-body.is-show { display: block; } .modal-close { position: absolute; top: -30px; right: 0; }
各要素にclassを付与してモーダルを表示させます。
JavaScript
$(function() { $('.modal-link').on('click', function() { var target = $(this).data('modaibody'); $('html').addClass('is-fixed'); $('.modal-bg').addClass('is-show'); $('.modal-contents').addClass('is-show'); $('#' + target).addClass('is-show'); }); $('.modal-close').on('click', function() { $('html').removeClass('is-fixed'); $('.modal-bg').removeClass('is-show'); $('.modal-contents').removeClass('is-show'); $('.modal-body').removeClass('is-show'); }); });
htmlとbodyにoverflow: hidden;を指定することでPCではスクロールできないようにできるのですが、iOSではスクロールできてしまいます。
うまくいかなかった場合のデモページ
対応方法
htmlとbodyにoverflow: hidden;と合わせてheight: 100%;を指定するといいようです。
CSS
html.is-fixed, html.is-fixed body { height: 100%; overflow: hidden; }
ただしこの方法の場合、モーダルを開くとスクロール位置がページトップに戻ってしまいます。
ヘッダーで使用するハンバーガーメニューなどの場合は問題なさそうですが、ページの下部の方にあるモーダルなどの場合には使えません。
この対応方法として、モーダルを開く前のスクロール位置を取得して、閉じた際にスクロール位置を元に戻すことで一応対応はできました。
JavaScript
$(function() { var scrollPos; $('.modal-link').on('click', function() { scrollPos = $(window).scrollTop(); var target = $(this).data('modaibody'); $('html').addClass('is-fixed'); $('.modal-bg').addClass('is-show'); $('.modal-contents').addClass('is-show'); $('#' + target).addClass('is-show'); }); $('.modal-close').on('click', function() { $('html').removeClass('is-fixed'); $('.modal-bg').removeClass('is-show'); $('.modal-contents').removeClass('is-show'); $('.modal-body').removeClass('is-show'); $(window).scrollTop(scrollPos); }); });
スクロール位置対応後のデモページ
ただこの方法でもモーダルを開いている時はスクロール位置がページトップに戻っているので、モーダルの背景が半透明の場合など、デザインによっては違和感があるかもしれません。
【参考サイト】
コメントが承認されるまで時間がかかります。