スクロールバーの幅を考慮したモーダル処理 [JavaScript]
どうもこんにちは fujihara です。
新年度が幕を明けましたね。春独特の夜の飲み会のザワツキを感じると
春だなぁ~って思います。(お酒はほとんど口にしませんが空気は嫌いじゃないです)
本日はモーダルを開いたときにスクロールを止めるために body に overflow:hidden をあてると
スクロールバーが非表示になり『ガタッ』ってなるのを防ぐ処理をご紹介します。
個人的にはモーダル最終章だと位置づけています。
概要
処理内容は以下のとおりです。
- モーダルを開くボタンを押す
- bodyのoverflow:hiddenをあてる前のclientWidthを取得
- bodyにoverflow:hiddenをあてる。(スクロールを不可に)
- bodyのclientWidthを再度取得
- overflow:hidden前後でのclientWidthの値が0より大きい場合スクロールバーを考慮したpadding-rightをbodyにあてる
- モーダルを閉じる時はpadding-rightを初期化する
コード
コードは以下のようになります。
HTML
<body style="height:8000px;"> <!-- 意図的にスクロールバーを出す -->
<div style="width:400px;height:300px;background-color:purple;margin-left:10%;margin-bottom:30px;"></div>
<button class="openModal" data-scrollbar="true">Open Modal(スクロールバー考慮)</button>
<div id="modal" class="modal">
<div class="modal-content">
<span id="closeModal" class="close">×</span>
<p>モーダルコンテントの中身</p>
</div>
</div>
</body>
CSS(※WC.CSS Modalから)
.modal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgb(0,0,0);
background-color: rgba(0,0,0,0.4);
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
}
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
JavaScript
var modal = document.querySelector('#modal');
var btn = document.querySelectorAll(".openModal");
var span = document.querySelector("#closeModal");
var body = document.body;
var clientWidth = body.clientWidth;
var noScrollBarWidth = clientWidth;
var diff = 0;
//モーダル開く処理
var openModal = function() {
//スクロールバーを無くす前
clientWidth = body.clientWidth;
body.style.overflow = 'hidden';
//スクロールバーを無くした後
noScrollBarWidth = body.clientWidth;
//スクロールバーの長さ計算
diff = noScrollBarWidth - clientWidth;
if (diff > 0) {
body.style['padding-right'] = diff + 'px';
}
modal.style.display = "block";
};
//modal 閉じる処理
var closeModal = function() {
body.style.overflow = 'auto';
body.style['padding-right'] = '0px';
modal.style.display = 'none';
};
//modal開くアクション
btn.forEach(function(eachBtn) {
eachBtn.addEventListener('click', function() {
openModal();
});
});
//modal閉じるアクション
span.addEventListener('click', function() {
closeModal();
});
//modal閉じるアクション(背景クリック時)
window.addEventListener('click', function(e) {
if (e.target === modal) {
closeModal();
}
});
まとめ
以下のリンク先にスクロールバーを考慮してる・していないもののサンプルを作成しましたので確認してみてください。 サンプル スクリプト内では overflow:hidden前後の差分を見て反映していますが、スクロールバーの幅とかけ離れていたり、 元々body に padding-right が当たっていた場合などを考慮していませんので独自に改良をしてみて下さい。