今回はモーダルウィンドウの作り方を紹介します。
モーダルウィンドウというのは下のCodePenのように、ボタンを押すと現れるウィンドウで、コレが開いている間はモーダル以外の領域を一切操作でなくなる特徴があります。
See the Pen Untitled by Satoru Shimizu (@sat-simizu) on CodePen.
フェードインで現れるモーダルウィンドウ
まずは、もっともシンプルなフェードで現れるモーダルウィンドウから紹介していきます。
このモーダルウィンドウの動作やコードは下のCodePenで確認してみて下さい。
See the Pen modal-fade by Satoru Shimizu (@sat-simizu) on CodePen.
ここで紹介するモーダルウィンドウの機能や特徴を下にまとめておきます。
- フェードインで現れ、フェードアウトで閉じる
- モーダルが開いている時は背景が暗くなる
- モーダルウィンドウが開いている間は背景位置はロックされて現在の位置からスクロールできなくなる
- モーダルウィンドウの外側をクリックするとモーダルウィンドウが閉じる
- モーダルウィンドウ内にある閉じるボタンをクリックしてもモーダルは閉じる
- キーボードのESCキーを押してもモーダルは閉じる
HTML
HTMLのコードは下記のとおりです。
<body>
<!-- モーダルのボタン -->
<button type="button" class="modal-btn">ボタン</button>
<!-- モーダルウインドウ/フェードイン -->
<div class="modal">
<!-- モーダルウインドウ/背景 -->
<div class="modal-bg modal-close"></div>
<!-- モーダルウインドウ/コンテンツ -->
<div class="modal-main-container">
<div class="modal-main-contents">
<!-- 閉じるボタン -->
<div class="modal-close-btn__wrapper">
<button class="modal-close-btn modal-close">閉じる</button>
</div>
<!-- スクロール用のタグ -->
<div class="modal-scroll__container">
<!-- コンテンツ例(自由に作って良い) -->
<div class="currency-wrapper">
<h2 class="currency__h2">通貨を選択してください</h2>
<ul class="currency-item__wrapper">
<li class="currency__item active">日本円</li>
<li class="currency__item">イスラエル新シェケル</li>
<li class="currency__item">インドルピー</li>
<li class="currency__item">ウルグアイペソ</li>
<li class="currency__item">エミラティディルハム</li>
<li class="currency__item">カナダドル</li>
<li class="currency__item">クロアチアクーナ</li>
<li class="currency__item">コスタリカコロン</li>
<li class="currency__item">コロンビアペソ</li>
<li class="currency__item">サウジアラビアリアル</li>
<li class="currency__item">シンガポールドル</li>
<li class="currency__item">スイスフラン</li>
<li class="currency__item">スウェーデンクローナ</li>
<li class="currency__item">タイバーツ</li>
<li class="currency__item">チェココルナ</li>
<li class="currency__item">チリペソ</li>
<li class="currency__item">デンマーククローネ</li>
<li class="currency__item">トルコリラ</li>
<li class="currency__item">ニュージーランドドル</li>
<li class="currency__item">ニュー台湾ドル</li>
<li class="currency__item">ノルウェークローネ</li>
<li class="currency__item">ハンガリーフォリント</li>
<li class="currency__item">フィリピンペソ</li>
<li class="currency__item">ブラジルレアル</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<!-- jqueryのスクリプト -->
<script src="https://code.jquery.com/jquery-3.6.1.min.js"
integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" crossorigin="anonymous"></script>
<!-- このサイトのスクリプト -->
<script src="./script.js"></script> -->
</body>
HTML構造について
HTMLの構造を必要不可欠な要素だけに単純化すると、下のとおりです。
<body>
<!-- モーダルを開くボタン -->
<button type="button" class="modal-btn">ボタン</button>
<!-- モーダルウインドウ/フェードイン -->
<div class="modal">
<!-- モーダルウインドウ/暗い背景 -->
<div class="modal-bg modal-close"></div>
<!-- モーダルウインドウ/コンテンツ本体 -->
<div class="modal-main-container">
<!-- 閉じるボタン -->
<div><button class="modal-close-btn modal-close">閉じる</button></div>
<!-- コンテンツ -->
<div>自由に作って良い</div>
</div>
</div>
</body>
CSS
モーダルの動作に必要な箇所のCSSは下記のとおりです。
body {
font-family: "Noto Sans JP", "メイリオ", "Meiryo", "MS ゴシック",
"Hiragino Kaku Gothic ProN", "ヒラギノ角ゴ ProN", sans-serif;
}
/* スクロールロックする時 */
body.fixed {
position: fixed;
width: 100%;
height: 100%;
}
/* モーダルを開くボタン */
.modal-btn {
display: flex;
justify-content: center;
align-items: center;
line-height: 1.8;
padding: 20px;
background-color: #333;
color: #fff;
border-radius: 5px;
max-width: 300px;
margin: 20px auto;
}
/*----------------------------------------------------------*/
/* モーダルウインドウ fade */
/*----------------------------------------------------------*/
/* モーダルウインドウ全体を囲うタグ */
.modal{
display: none;
}
/* モーダルウインドウ/暗い背景 */
.modal-bg {
width: 100%;
height: 100%;
background-color: rgba(0,0,0, 0.6);
position: fixed;
top: 0;
left: 0;
z-index: 10;
transition: .3s;
}
/* モーダルウインドウ/コンテンツ */
.modal-main-container {
color: black;
z-index: 11;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
max-width: 1032px;
width: 90%;
height: 60%;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.modal-main-contents {
background-color: #fff;
max-width: 1032px;
border-radius: 12px;
height: 100%;
display: flex;
flex-direction: column;
box-shadow: rgba(0, 0, 0, 0.28) 0px 8px 28px;
transition: .3s;
}
/* モーダルウインドウ/閉じるボタンのwrapper */
.modal-close-btn__wrapper {
border-bottom: solid 1px #ebebeb;
height: 64px;
display: flex;
align-items: center;
}
/* モーダルウインドウ/閉じるボタン */
.modal-close-btn {
color: black;
cursor: pointer;
margin-left: 24px;
}
フェード型モーダルのCSS
- 背景スクロールのロック:bodyにクラスfixedを付与したときにposition: fixedになる
- モーダル全体:初期状態はdisplay: none;で非表示
- モーダル本体とモーダルの暗い背景のz-indexに注意:モーダルの暗い背景のz-indexはモーダル以外の要素より大きくし、モーダル本体はモーダル背景よりも更に大きい数値に設定する。
jQuery
コードは下記のとおりで、比較的シンプルです。沼りやすいポイントは背景スクロールのロックですね。
$(function() {
var scrollPos;//topからのスクロール位置
$('.modal-btn').click(function() { //ボタンをクリックしたら
scrollPos = $(window).scrollTop();//topからのスクロール位置を取得
$('.modal').fadeIn();//モーダルをフェードイン
$('body').addClass('fixed').css({ top: -scrollPos });//背景固定
return false;//<a>を無効化
});
$('.modal-close').click(function() { //閉じるまたは背景をクリックしたら
$('.modal').fadeOut();//モーダルをフェードアウト
$('body').removeClass('fixed').css({ top: 0 });//背景固定を解除
$(window).scrollTop(scrollPos);//元の位置までスクロール
return false;//<a>を無効化
});
$(window).keyup(function(e){//キーをクリックして
if(e.keyCode == 27){//ESCキーだったら
$('.modal').fadeOut();//モーダルをフェードアウト
$('body').removeClass('fixed').css({ top: 0 });//背景固定を解除
$(window).scrollTop(scrollPos);//元の位置までスクロール
}
});
});
背景のスクロールロックについて
モーダルで一番厄介なのが、背景スクロールのロックです。
ここでは、モーダルを開くボタンをクリックした時点でスクロール位置を取得し、そのスクロール位置で背景を固定(position: fixed)するようにコーディングしています。
その手順を順番に箇条書きすると下のとおりです。
- 最初に変数宣言:var scrollPos(名称は自由:topからのスクロール位置)
- モーダルを開くボタンをクリックしたら:$(‘.modal-btn’).click(function() {…
- 現在のスクロール位置を取得:scrollPos = $(window).scrollTop();
- 背景固定:bodyにクラスfixedを付与して背景スクロールを現在の位置で固定:$(‘body’).addClass(‘fixed’).css({ top: -scrollPos });
- 閉じるボタン・またはモーダルの背景をクリックしたら:$(‘.modal-close’).click(function() {…
- 背景スクロールのロック解除:bodyにクラスfixedを剥奪してtopから0のスクロール位置へ:$(‘body’).removeClass(‘fixed’).css({ top: 0 });
- 元の位置までスクロール$(window).scrollTop(scrollPos);
背景スクロールをロックする方法には、「overflow-y: hidden;」を使う人もいますが、これではiOS端末でスクロールロックができないため注意が必要です。
モーダルのフェードイン
方法自体は、クリックイベントを監視して、初期状態display:none;からjQueryのfadeIn()とfadeOut()メソッドを使う一般的なものです。
- モーダルを開くボタンをクリックしたら:$(‘.modal-btn’).click(function() {…
- モーダル(モーダル本体と暗い背景)をフェードイン:$(‘.modal’).fadeIn(); →この.modalというクラスのタグはモーダル全体(モーダル本体と暗い背景)を囲うタグ。初期状態はdisplay:none;で非表示にしてある。
- 閉じるボタンまたは暗い背景をクリックしたら:$(‘.modal-close’).click(function() {… →この.modal-closeクラスは閉じるボタンと暗い背景に付けおく。
- モーダル(モーダル本体と暗い背景)をフェードアウト:$(‘.modal’).fadeOut();
キーボードのESCキーを押してモーダルが閉じるjQuery
キーボードの特定のキーを押して特定の処理を行うには、jQueryの決り文句の構文があります。
$(window).keyup(function(e){////キーボードのキーを押して
if(e.key === "Escape"){//ESCキーだったら
//ここに処理を書く
}
});
処理の内容はクリックイベントの閉じるの内容と全く同じです。
一応関係箇所のjQueryの抜粋コードを書いておきます。
$(window).keyup(function(e){////キーボードのキーを押して
if(e.key === "Escape"){//ESCキーだったら
$('.modal').fadeOut();//モーダルをフェードアウト
$('body').removeClass('fixed').css({ top: 0 });//背景固定を解除
$(window).scrollTop(scrollPos);//元の位置までスクロール
}
});
下から出てくるモーダルウィンドウ
次に下から現れるスライドインで現れるモーダルを紹介します。
フェード型モーダルを少し改良するだけで簡単に作れます。
このモーダルウィンドウの動きとコードはCodePenで確認してみて下さい。
See the Pen modal-slideIn by Satoru Shimizu (@sat-simizu) on CodePen.
このモーダルウィンドウの機能的な特徴は上で紹介したフェードタイプと同じです。現れ方が違うだけ。
一応、書き出すと次のような感じです。
- ボタンクリックで下からスライドインで現れる
- モーダルが開いている間は背景のスクロールがロックされ、現在の位置からスクロールできなくなる
- モーダルの外側をクリックすると、モーダルが閉じる
- モーダル内の閉じるボタンをクリックしても、モーダルは閉じる
- モーダルが開いている間は背景が暗くなる
HTML|下から出てくるモーダルウィンドウ
HTMLはフェード型モーダルと全く同じです。
CSS|下からスライドインで出てくるモーダルウィンドウ
fade型との違いは、モーダル本体の初期状態の位置は画面の下に隠しておき、これに特定のクラス(今回はslide)が付与されると、表示位置が画面中央に切り替わる点です。
body {
font-family: "Noto Sans JP", "メイリオ", "Meiryo", "MS ゴシック",
"Hiragino Kaku Gothic ProN", "ヒラギノ角ゴ ProN", sans-serif;
}
/* スクロールロックする時 */
body.fixed {
position: fixed;
width: 100%;
height: 100%;
}
/* モーダルを開くボタン */
.modal-btn {
display: flex;
justify-content: center;
align-items: center;
line-height: 1.8;
padding: 20px;
background-color: #333;
color: #fff;
border-radius: 5px;
max-width: 300px;
margin: 20px auto;
}
/*----------------------------------------------------------*/
/* モーダルウインドウ Slide In */
/*----------------------------------------------------------*/
/* モーダルウインドウ全体を囲うタグ */
.modal{
display: none;
}
/* モーダルウインドウ/背景 */
.modal-bg {
width: 100%;
height: 100%;
background-color: rgba(0,0,0, 0.6);
position: fixed;
top: 0;
left: 0;
z-index: 10;
transition: .3s;
}
/* モーダルウインドウ/コンテンツ */
.modal-main-container {
color: black;
z-index: 11;
position: fixed;
top: 200%;
left: 50%;
transform: translate(-50%, -50%);
max-width: 1032px;
width: 90%;
height: 60%;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
transition: .3s;
}
.modal-main-container.slide{
top: 50%;
transition: .3s;
}
.modal-main-contents {
background-color: #fff;
max-width: 1032px;
border-radius: 12px;
height: 100%;
display: flex;
flex-direction: column;
box-shadow: rgba(0, 0, 0, 0.28) 0px 8px 28px;
transition: .3s;
}
/* モーダルウインドウ/閉じるボタンのwrapper */
.modal-close-btn__wrapper {
border-bottom: solid 1px #ebebeb;
height: 64px;
display: flex;
align-items: center;
}
/* モーダルウインドウ/閉じるボタン */
.modal-close-btn {
color: black;
cursor: pointer;
margin-left: 24px;
}
下からスライドインで出てくるモーダルのCSSの要点
フェード型との違いはわずかで、モーダル本体の初期の表示位置と、slideクラスが付与されたときの表示位置の2箇所だけです。
- モーダル本体初期状態の表示位置:画面下に隠れている
.modal-main-container {
position: fixed;
top: 200%;
left: 50%;
transform: translate(-50%, -50%);
} - モーダル本体にslideクラスが付与されたときの表示位置:画面中央に表示される
.modal-main-container.slide{
top: 50%;
}
jQuery|下から出てくるモーダルウィンドウ
フェード型モーダルとの違いは、スライドイン・アウトに関する行が増えただけです。
$(function() {
var scrollPos;//topからのスクロール位置
$('.modal-btn').click(function() { //ボタンをクリックしたら
scrollPos = $(window).scrollTop();//topからのスクロール位置を取得
$('.modal').fadeIn();//モーダル背景をフェードイン
$('.modal-main-container').addClass('slide');//モーダル本体をスライドイン
$('body').addClass('fixed').css({ top: -scrollPos });//背景固定
return false;//<a>を無効化
});
$('.modal-close').click(function() { //閉じるまたは背景をクリックしたら
$('.modal').fadeOut();//モーダル背景をフェードアウト
$('.modal-main-container').removeClass('slide');//モーダル本体をスライドアウト
$('body').removeClass('fixed').css({ top: 0 });//背景固定を解除
$(window).scrollTop(scrollPos);//元の位置までスクロール
return false;//<a>を無効化
});
$(window).keyup(function(e){//キーボードのキーを押して
if(e.key === "Escape"){//ESCキーだったら
$('.modal').fadeOut();//モーダル背景をフェードアウト
$('.modal-main-container').removeClass('slide');//モーダル本体をスライドアウト
$('body').removeClass('fixed').css({ top: 0 });//背景固定を解除
$(window).scrollTop(scrollPos);//元の位置までスクロール
}
});
});
下からスライドインで出てくるモーダルのjQueryの要点
フェード型と違う点は下のとおりです。
モーダルを開くボタンをクリックしたら
- モーダル本体をスライドイン:モーダル本体(.modal-main-container)にslideクラスを付与
$(‘.modal-main-container’).addClass(‘slide’);
モーダルを閉じるボタンあるいはモーダルの暗い背景をクリックしたら
- モーダル本体をスライドアウト:モーダル本体(.modal-main-container)からslideクラスを剥奪
$(‘.modal-main-container’).removeClass(‘slide’);
キーボードのESCキーを押したら
- $(‘.modal-main-container’).removeClass(‘slide’);
動画のモーダルウィンドウ
続いて動画のモーダルウィンドウ。
このタイプはAirBnbのサイトなどで見られます。
下にこのモーダルウィンドウのCodePenを置いておきますので、動作とコードを確認してみて下さい。
See the Pen modal-movie2 by s sim (@s-sim) on CodePen.
この動画モーダルウィンドウの制御は上で紹介した2つよりも少し複雑です。
動画モーダルの機能を書き出すと下のようになります。
- モーダルウィンドウを開くと同時に動画が再生され始める
- 動画画面クリックで停止・再生操作ができる
- モーダルウィンドウを閉じて、次にモーダルを開いた時に動画の頭出しが完了している
- モーダル外側をクリックするとモーダルが閉じ、動画が停止・頭出しが完了する
- モーダル内の閉じるボタンでも同じ
- モーダルが開いている間は背景が暗くなる
- モーダルを開いている間はモーダル外側の背景がスクロールできなくなる
作り方は単純で、フェード型モーダルに動画再生・停止・頭出しの命令を加えるだけです。
HTML|動画のモーダルウィンドウ
動画モーダルの基本構造もフェード型モーダルと全く同じです。
<body>
<!-- モーダルを開くボタン -->
<button type="button" class="movie-btn">動画ボタン</button>
<!-- モーダルウインドウ全体を囲うタグ -->
<div class="modal-movie">
<!-- モーダルウインドウの暗い背景 -->
<div class="modal-movie-bg modal-movie-close"></div>
<!-- モーダルウインドウのコンテンツ -->
<div class="modal-movie-body">
<!-- 閉じるボタン -->
<div class="movie-close-btn modal-movie-close">閉じる</div>
<!-- モーダル内コンテンツ(動画) -->
<div class="modal-movie__content">
<video class="movie" autoplay controls style="object-fit: contain; width: 100%; height: 100%">
<source type="video/mp4" src="https://shimizu-create.com/wp-content/uploads/2024/03/movie-sample2.mp4">
<source type="video/webm" src="wp-content/uploads/2024/03/movie-sample2.webm">
</video>
</div>
</div>
</div>
<!-- jqueryのスクリプト -->
<script src="https://code.jquery.com/jquery-3.6.1.min.js"
integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" crossorigin="anonymous"></script>
</body>
動画モーダルのHTMLの要点
他のモーダルとの違いは、モーダルのコンテンツ部分が動画ファイルのvideoタグと置き換わるだけです。
vodioタグの設定は人それぞれですが、上の例では、動画の縦横比固定、動画自動再生、ファイル形式はmp4とwebmの2つを用意しています。
- autoplay:自動再生
- controls:再生、音量、シーク、ポーズの各機能を制御するコントロールを表示
- style=”object-fit: contain; width: 100%; height: 100%” :縦横比固定
- source type=”video/mp4″ src=”…:ファイル形式はmp4
- source type=”video/webm” src=…”ファイル形式はwebm
CSS|動画のモーダルウィンドウ
動画モーダルのCSSはフェード型モーダルとほぼ同じですので説明を省略します。
コードの詳細はCodePenを参照して下さい。
jQuery|動画のモーダルウィンドウ
動画モーダルのjQueryの構文は、フェード型モーダルに動画の再生・一時停止・頭出しの命令を加えただけしか違いはありません。
// モーダルウィンドウ動画
$(function() {
var scrollPos;//topからのスクロール位置
$('.movie-btn').click(function() { //ボタンをクリックしたら
scrollPos = $(window).scrollTop();//topからのスクロール位置を取得
$('.modal-movie').fadeIn();//モーダル背景をフェードイン
$('body').addClass('fixed').css({ top: -scrollPos });//背景固定
$('.movie')[0].play();//開くボタンをクリックしたら動画を再生する
return false;//<a>を無効化
});
$('.modal-movie-close').click(function() { //閉じるまたは背景をクリックしたら
$('.modal-movie').fadeOut();//モーダル背景をフェードアウト
$('body').removeClass('fixed').css({ top: 0 });//背景固定を解除
$(window).scrollTop(scrollPos);//元の位置までスクロール
$('.movie')[0].pause();//ビデオを停止
$('.movie')[0].currentTime = 0;//頭出し
return false;//<a>を無効化
});
});
モーダルを開くボタンをクリックしたら
- 動画を再生:クラス.movieのvideoタグの動画がターゲット
$(‘.movie’)[0].play();
モーダルを閉じるボタンあるいはモーダルの暗い背景をクリックしたら
- 動画を停止・頭出し:クラス.movieのvideoタグの動画がターゲット
$(‘.movie’)[0].pause(); →ビデオを停止
$(‘.movie’)[0].currentTime = 0; →頭出し
複数のモーダルウィンドウを設置
今日紹介したモーダルウィンドウのコードは、もちろん複数設置する場合にも使えます。
下にモーダルを複数設置したCodePenを置いて置くので確認してみて下さい。
See the Pen modal-multiple by s sim (@s-sim) on CodePen.
コードは単独設置と比べて注意点はクラス名を各モーダルで重複しないようにすることです。
なお、背景ロックにつかうクラスfixedは共通でも動きます。
まとめ
以上、よく使いそうなテキストや動画のモーダルウィンドウの作り方を紹介しました。
モーダルウィンドウもシンプルなものであれば簡単につくれますが、細かい機能を足していくとコードも複雑になりますね。今回紹介したのは、他にも応用が効きやすいように比較的複雑なものを紹介しました。