【Safari考慮完全版】モーダルウィンドウの実装(jQuery編)

ロッチくん
ロッチくん

モーダルウィンドウ出現時に背景をスクロールしないようする方法とスクロールバーの幅分背景がガタつくのを回避する方法を知りたいニャ

最初に

モーダルウィンドウの実装方法を以前紹介したのですが、こちらの方法で使用したモーダル出現時に背景をスクロールできないようロックする手法はiOSのバージョン16より前のSafariで使用できませんでした。バージョン16より前のSafariを使用している方もまだ2割ほどいるとのことで簡単に無視できない割合ではあります。

↓↓↓ 以前紹介したモーダルウィンドウの実装方法 ↓↓↓

また、背景を固定するときに、モーダルが出たり消えたりするたびにスクロールバーの幅分画面ががたつく現象がありました。こちらを回避するために使用したCSSのプロパティ「scrollbar-gutter: stable;」も現状ではSafariで使用できません。

以上2点を考慮してかつ、初心者の方にもわかりやすい方法を自分なりに解説したいと思います。

こちらが今回の記事で紹介したコードで実装されたデモページになります。

コード

HTML

<div class="wrapper">
    <div class="container">
        <div class="overlay"></div>
        <div class="mordalContents" id="contents1">
            <p>ここにモーダルコンテンツ1の内容が入ります。</p>
            <button class="closeBtn btn">閉じる</button>
        </div>
        <div class="mordalContents" id="contents2">
            <p>ここにモーダルコンテンツ2の内容が入ります。</p>
            <button class="closeBtn btn">閉じる</button>
        </div>
        <div class="mordalContents" id="contents3">
            <p>ここにモーダルコンテンツ3の内容が入ります。</p>
            <button class="closeBtn btn">閉じる</button>
        </div>

        <button class="openBtn btn" data-id="contents1">オープン1</button>

        <button class="openBtn btn" data-id="contents2">オープン2</button>

        <button class="openBtn btn" data-id="contents3">オープン3</button>
    </div>
</div>

HTMLは以前の記事で紹介したコードと変わりません。

CSS

/* html {
  scrollbar-gutter: stable;
} */
/* body.noScroll {
  overflow: hidden;
} */
body {
  width: 100%;
  overflow-y: scroll;
}
.container {
  padding-top: 100px;
  padding-bottom: 100px;
  position: relative;
}
.overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0,0,0,.6);
  opacity: 0;
  visibility: hidden;
  transition: all .3s;
  z-index: 9;
}
.overlay.show {
  opacity: 1;
  visibility: visible;
}
.mordalContents {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: #eee;
  border-radius: 15px;
  width: 450px;
  height: 450px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  row-gap: 65px;
  opacity: 0;
  visibility: hidden;
  transition: all .3s;
  z-index: 10;
}
.mordalContents.open {
  opacity: 1;
  visibility: visible;
}
.btn {
  width: 250px;
  height: 50px;
  display: block;
  margin: 0 auto;
  border-radius: 35px;
  color: #fff;
  text-align: center;
}
.closeBtn {
  background-color: rgb(54 50 217);
}
.openBtn {
  background-color: rgb(234, 55, 55);
  margin-top: 250px;
  margin-bottom: 250px;
}

@media (max-width: 768px) {
  .mordalContents {
    width: 330px;
    height: 330px;
  }
  .mordalContents p {
    font-size: 14px;
  }
}

CSSの変更点はこちらだけ

/* html {
  scrollbar-gutter: stable;
} */
/* body.noScroll {
  overflow: hidden;
} */
body {
  width: 100%;
  overflow-y: scroll;
}

Safariで使えないコードをコメント化し、bodyに「width: 100%;」と「overflow-y: scroll;」を指定しスクロールバーを常時出しておくようにしています。

JavaScript

const body = $("body");
const overlay = $(".overlay");
let scrollY;
// const scrollBarWidth = window.innerWidth - document.body.clientWidth;
$(".openBtn").on("click", function() {
  let id = "#" + $(this).data("id");
  overlay.addClass("show");
  $(id).addClass("open");
  scrollY = $(window).scrollTop();
  body.css( {
    "position": "fixed",
    "top": -scrollY,
    // "paddingRight": scrollBarWidth + "px"    
  });
});

$(".closeBtn, .overlay").on("click", function() {
  overlay.removeClass("show");
  $(".mordalContents").removeClass("open");
  body.css( {
    "position": "",
    "top": "",
    // "paddingRight": 0    
  });
  $(window).scrollTop(scrollY);
});

巷で紹介されているものより極力シンプルにわかりやすくしているつもりです。

コメント化されている部分は、さっきbodyに「overflow-y: scroll;」を指定しスクロールバーを常時出しておく方法を使わなかった場合に、モーダル出現時にスクロールバーの幅分のパディングを右に指定するという方法を実装する場合に使います。どちらでも同じような効果が得られますが、今回はjsをよりシンプルにしたかったのでやめました。

bodyに「overflow: hidden;」を使う方法の代わりに、モーダルが押された場所のY軸方向の距離(=$(window).scrollTop();)を取得しその位置で、bodyを「position: fixed;」し固定するという手法です。そしてモーダル解除時にはいったん固定を解いて再度スクロール位置(最初にモーダルが押された位置)に再スクロールして戻すという、言葉にすると手間なことをやっています。

モーダルウィンドウの実装自体は比較的単純なのに、背景をロックするととたんに面倒くさい記述が増えてきますね。今回はできるだけ簡潔で分かりやすい記述におさめたつもりですがいかがだったでしょうか?

iOSのバージョン16以降ではbodyに「overflow: hidden;」することで解決できるので今後このような面倒な記述は必要なくなると思いますが、まだこちらの方法が使わることになると思います。

jQueryを用いた頻出UIまとめた記事はこちらから!最低限こちらを実装できればWEB制作の現場でもそんなに困らないかと思います!!

コメント

タイトルとURLをコピーしました