モーダルウィンドウの実装(jQuery編)

ロッチくん
ロッチくん

ボタンをクリックするとポップアップで小窓が開くタイプのUIを実装してみたいニャ

ボタンをクリックすることで、背景が暗くなった上に小窓が開き重要なお知らせなどユーザーの注意を引きやすいコンテンツを表示させることができるモーダルウィンドウの実装方法を解説します。

はじめに

こちらのUIは上記のようにユーザーの注意を引きやすいものですが、ユーザーが何らかの動作を強いる強制力もあるため、ログイン画面への導線や、重要なお知らせなど限られたものにのみ使用し多用しないことが望ましいです。

こちらもCSSのみで実装することも可能なのですが、今回はjQueryを用いた簡単なやり方を紹介します。

まずjQueryを読み込ませます。解説はこちらから↓

そして今回実装したいデモページはこちら同一ページ内に複数のモーダルウィンドウを設置するケースを想定しており、またモーダル起動時にはページをロックする仕様にしております。

それでは実際にコードを見ていきましょう!

コード

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>

CSS

html {
  scrollbar-gutter: stable;
}
body.noScroll {
  overflow: hidden;
}
.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;
}

JavaScript

$(".openBtn").on("click", function() {
  let id = "#" + $(this).data("id");
  $(".overlay").addClass("show");
  $(id).addClass("open");
  $("body").addClass("noScroll");
});

$(".closeBtn, .overlay").on("click", function() {
  $(".overlay").removeClass("show");
  $(".mordalContents").removeClass("open");
  $("body").removeClass("noScroll");
});

オープンボタンに付いているdata-id属性というのをあまり見ないかもしれませんが、data-…とした属性はその要素に意味のある情報を付与することができます。この場合モーダルを開くボタンにdata-id属性を付与し、対応したモーダルの側にはそれと同じ値のidを付すことで、それぞれを連動させることができます。

ちょこっと解説

モーダルとオーバーレイする背景の挙動は、最初に要素をdisplay: none; で非表示にしておいて、jQueryのfadeIn(); fadeOut(); メソッドを使う方法もあります。

ただ今回はモーダルコンテンツをdisplay: flex;でフレックスコンテナ化しているため、この手法は使えませんでした。

fadeIn();メソッドを適用された要素はdisplay: block;となりブロック要素となるため、display: flex;を上書きしてしまうからです。

ですから今回は要素を「opacity: 0;」の「visivility: hidden;」でいったん消しておいて、クラス付与で表示させる手法を使っています。もし、モーダルコンテンツをフレックスコンテナにしていない場合はfadeIn(); fadeOut(); メソッドでも問題ありません。

また、CSSに

html {
  scrollbar-gutter: stable;
}

という見慣れない記述があるかと思います。

こちらは、モーダル出現時に背景をロックしてスクロールを止めた状態のときに、右のスクロールバーの横幅分画面ががたつくことの対策として入れてます。

scrollbar-gutter: stable;を指定しないとこのようにガタつきます。

scrollbar-gutterは、スクロールバー出現分の余白を制御できるプロパティで、bodyがoverflow: hidden;してスクロールバーがなくなった分のスペースを確保してくれるというわけです。

ただ、今のところscrollbar-gutterはSafariでは利用できないようです。

これを別の方法で解決する手法もあるのですが、やや複雑になるのでまたの機会にしたいと思います。

上記を解決する記事を書きましたのでこちらご参照ください!

とりあえず今回は基本的なやり方を覚えておきましょう。

最後に

現場でもCSSのみで実装したりすることも最近はあるのでそちらの方法もいずれ紹介したいと思います。

ただCSSのみだとモーダル起動時の背景のロックができないといった点もありますが、jQueryを使わなくていいので軽くて手軽というメリットもあります。

今回紹介したやり方でもモーダル起動時の背景ロックを回避するやり方もSafariでは効かないので、背景ロック自体どうしても必要というわけでもないと思うので諦めるという選択肢もあるでしょう。

また、今回背景のロックのためにbodyに使った「overflow: hidden;」はiOSのSafariで使えないといった問題点もあります。日本でも市場を考えたときにiPhone、iPadを考慮しないのはなかなか難しいので違う方法を検討する必要がありそうです。

※ただし2022年登場した現在はiOSのバージョン16からは上記方法でも実装可能となりました。

ただ先ほども告知したようにSafariを考慮した背景ロックの方法を解説の予定ですので、お待ちいただければと思います!

上記を解決する記事を書きましたのでこちらご参照ください!

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

コメント

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