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);
});
});
スクロール位置対応後のデモページ
ただこの方法でもモーダルを開いている時はスクロール位置がページトップに戻っているので、モーダルの背景が半透明の場合など、デザインによっては違和感があるかもしれません。
【参考サイト】
コメントが承認されるまで時間がかかります。