初心者でも簡単!モーダルウィンドウの作り方

モーダルウィンドウの作り方 jQuery・JavaScript

モーダルウィンドウは、コンテンツを浮かび上がるようにポップアップ表示させることができます。
ヘルプやアラートなど、ちょっとしたメッセージを表示するときに、確認ダイアログだとちょっとダサい・・・。そんな時に使えると便利なのがモーダルウィンドウです。

モーダルウィンドウのデモ

テキストリンクをクリックすると、モーダルウィンドウが表示されます。コンテンツ内の閉じるボタン、または背景のオーバーレイをクリックすると、モーダルウィンドウを閉じます。

クリックするとモーダルウィンドウを開きます。

モーダルウィンドウの作り方

コンテンツの作成

まずは、モーダルウィンドウ内に表示させるコンテンツを作成します。あとから変更することができるので、現段階ではこだわる必要はありません。

<div id="modal-content">
	<p>「閉じる」か「背景」をクリックするとモーダルウィンドウを終了します。</p>
	<p><a id="modal-close" class="button-link">閉じる</a></p>
</div>
#modal-content {
	width: 50% ;
	margin: 0 ;
	padding: 10px 20px ;
	border: 2px solid #aaa ;
	background: #fff ;
	position: fixed ;
	display: none ;
	z-index: 2 ;
}

手前に表示させる

コンテンツを囲むdiv要素にはz-indexの値を設定します。z-indexとは、「手前、奥」の概念です。z-indexの値が高いほど、そのコンテンツは、値が低い他のコンテンツよりも手前に表示されることになります。
初期値は0(または親要素と同じ)です。

モーダルウィンドウのコンテンツは、通常表示されている他のコンテンツ(z-index:0)と、次項で作るオーバーレイ(z-index:1)よりも手前に表示させるので、2を指定しておきましょう。もし、他のライブラリなどを導入している関係で手前に上手く表示されない場合は、9999にするなど調整して下さい。

position:fixedを指定しておきます。これは、「対象の要素を指定した位置に固定する」という命令です。これは、ページをスクロールしても、ずっと画面上のその位置に止まり続けるという意味です。

画面上のどの位置に固定するかは、top(画面上部から何ピクセルか)と、left(画面左部から何ピクセルか)などで指定する仕組みですが、後ほど、jQueryによって動的に指定するので、現時点では指定しません。

オーバーレイの作成

続いて、オーバーレイの部分を作成していきます。先ほどのモーダルウィンドウのデモを表示した時に、周りの背景が半透明のグレーになっていて、そこをクリックするとウィンドウが閉じれたかと思います。
あの部分のことをオーバーレイと言います。

<div id="modal-overlay"></div>
#modal-overlay {
	z-index: 1 ;
	display: none ;
	position: fixed ;
	top: 0 ;
	left: 0 ;
	width: 100% ;
	height: 120% ;
	background-color: rgba( 0,0,0, 0.75 ) ;
}

HTMLの部分に関しては、後ほどJavaScriptにて動的に生成しますので、特にHTMLファイルに記述しておく必要はありません。あとからこのHTMLを呼び出すということを覚えておいて下さい。

今回のオーバーレイは、ページ全体ではなく画面全体を覆います。そのため、width:100%とheight:120%を指定し、さらにposition:fixedで位置を固定しておきましょう。

heightの指定を120%にしているのは、スマホ対策です。iPhoneではスクロールをすると上下のナビバーが隠れる仕組みになっているため、heightの値が変わってしまい、オーバーレイが画面の高さよりも小さくなってしまうという不具合が起こります。それを解消するため、余裕を持って120%の値を指定しています。

色を#D36015というような16進数(Hex)ではなく、rgbaで指定することで、不透明度を加えることができます。モーダルウィンドウを表示した時、コンテンツが背景にうっすらと映っている状態にするのに必要です。今回は、色を黒、不透明度0.75を指定したものです。()内の第1〜3引数がRGB指定による色、第4引数が不透明度を表します。

モーダルウィンドウを表示する

ここからいよいよ、JavaScriptを取り扱っていきます。jQueryを利用するので、

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>

<head></head>内にあらかじめ上記を記述しておきましょう。

ボタンを用意する

モーダルウィンドウを呼び出すためのボタンを用意しておきましょう。

<p><a id="modal-open" class="button-link">クリックするとモーダルウィンドウを開きます。</a></p>

クリックイベントの設定

ボタンをクリックした時にモーダルウィンドウを表示させるイベントを設定します。

$("#modal-open").click(
	function(){
		//ここにクリックしたら起こる処理
	}
);

オーバーレイを表示する

ボタンがクリックされた時にオーバーレイを表示するように設定していきます。さきほど、HTMLはjQueryで自動生成させると説明しましたが、具体的には、以下のように行います。

//キーボード操作などにより、オーバーレイが多重起動するのを防止する
$(this).blur() ;	//ボタンからフォーカスを外す
if($("#modal-overlay")[0]) return false ;		//新しくモーダルウィンドウを起動しない [下とどちらか選択]
//if($("#modal-overlay")[0]) $("#modal-overlay").remove() ;		//現在のモーダルウィンドウを削除して新しく起動する [上とどちらか選択]

//オーバーレイ用のHTMLコードを、[body]内の最後に生成する
$("body").append('<div id="modal-overlay"></div>');

//[$modal-overlay]をフェードインさせる
$("#modal-overlay").fadeIn("slow");

「クリックイベントの設定」でお話しした箇所に上記のコードを記述します。

appendは対象の要素内の最後に、指定したHTMLを追加する命令です。上記では、body要素内の最後に、オーバーレイのHTMLコードを追加しています。さらに、初期ではdisplay:hiddenで非表示状態なのを、fadeInにより、じんわりと表示させています。

コンテンツをセンタリングする

コンテンツを画面の真ん中に表示させるにはどうすればいいかを考えてみましょう。position:fixedのtop(画面上部から何ピクセル離れているか)とleft(画面左部から何ピクセル離れているか)の値を、上手く設定します。
例えば、画面幅が1000pxあって、コンテンツ幅が200pxある場合、真ん中に持ってくるには、left(片側の余白の値)に400pxを設定します。左端から400px離せばいいというわけです。縦幅も同じですね。「片側の余白」は次の計算で求めることができます。

(画面幅 – コンテンツ幅) ÷ 2

横幅、縦幅を求めてセンタリングするには、次の通り、処理しましょう。複数の場所から呼び出せるように、centeringModalSyncer()という関数にしてあります。このように、モーダルウィンドウを開いた時の画面幅に合わせてtopとleftの値を設定してやることで、センタリングが実現します。

//センタリングを実行する関数
function centeringModalSyncer() {

	//画面(ウィンドウ)の幅、高さを取得
	var w = $( window ).width() ;
	var h = $( window ).height() ;

	// コンテンツ(#modal-content)の幅、高さを取得
	// jQueryのバージョンによっては、引数[{margin:true}]を指定した時、不具合を起こします。
	var cw = $( "#modal-content" ).outerWidth( {margin:true} );
	var ch = $( "#modal-content" ).outerHeight( {margin:true} );
	var cw = $( "#modal-content" ).outerWidth();
	var ch = $( "#modal-content" ).outerHeight();

	//センタリングを実行する
	$( "#modal-content" ).css( {"left": ((w - cw)/2) + "px","top": ((h - ch)/2) + "px"} ) ;

}

モーダルウィンドウを終了する

モーダルウィンドウを終了させるクリックイベントを設定します。

クリックイベントの設定

オーバーレイ(#modal-overlay)と閉じるボタン(#modal-close)、2つの要素に同じクリックイベントを設定します。それには、セレクタをカンマで区切って、次のように記述します。

$("#modal-overlay,#modal-close").unbind().click(function(){
	//[#modal-overlay]、または[#modal-close]をクリックしたら起こる処理
});

click()の直前にあるunbind()は、対象の要素にそれまで設定されていたイベントをクリアする命令です。

フェードアウトさせる

オーバーレイとコンテンツをフェードアウトで非表示にした後に、HTML上からオーバーレイのHTMLを削除します。それには次の通り、命令しましょう。

//[#modal-content]と[#modal-overlay]をフェードアウトした後に…
$( "#modal-content,#modal-overlay" ).fadeOut( "slow" , function(){

	//[#modal-overlay]を削除する
	$('#modal-overlay').remove() ;

} ) ;

fadeOut()の第2引数に関数を指定することで、その関数がフェードアウトしたタイミングで実行されます。remove()は対象の要素をHTML上から削除する命令です。

まとめ モーダルウィンドウのサンプルコード

以上でモーダルウィンドウは完成です。
他にもコードを変えることでいろいろな使い道ができるので、いろいろといじってみてください。

最後に、今回のモーダルウィンドウのサンプルコードをまとめて記載しておきます。

HTMLのサンプル

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link href="css/style.css" rel="stylesheet" type="text/css" />
<title>モーダルウィンドウのデモ</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<link href="css/modal.css" rel="stylesheet">
<script src="js/modal.js"></script>
</head>
<body>
<div id="orver">
			<h1>モーダルウィンドウのデモ</h1>
	<div id="wrap">
		<div id="contents">
			<p>リンクテキストをクリックするとモーダルウィンドウを表示させます。モーダルウィンドウ周りのオーバーレイをクリックすると終了します。</p>
			<a id="modal-open" class="button-link">クリックするとモーダルウィンドウを開きます。</a>
		</div> <!-- contents end -->
	</div> <!-- wrap end -->
</div> <!-- orver end -->

<!-- ここからモーダルウィンドウ -->
<div id="modal-content">
	<div id="modal-content-innar">
	<!-- モーダルウィンドウのコンテンツ開始 -->
	<p class="red bold">モーダルウィンドウのデモ

これはモーダルウィンドウです。<br />左下の「閉じる」か、背景をクリックすると終了します。</p>

<p><a id="modal-close" class="button-link">閉じる</a></p>
	</div>
	<!-- モーダルウィンドウのコンテンツ終了 -->
</div>
</body>
</html>

CSSのサンプル

@charset "UTF-8" ;

/* ここからデモページ用のコード */
body {
	width: 100% ;
	padding: 0 ;
}
/* ここまでデモページ用のコード */

#modal-content {
	width: 50% ;
	margin: 0 ;
	padding: 10px 20px ;
	border: 2px solid #aaa ;
	background: #fff ;
	position: fixed ;
	display: none ;
	z-index: 2 ;
}

#modal-content-innar{
	margin:0 auto;
	width:80%;
}
  
#modal-overlay {
	z-index: 1 ;
	display: none ;
	position: fixed ;
	top: 0 ;
	left: 0 ;
	width: 100% ;
	height: 120% ;
	background-color: rgba( 0,0,0, 0.75 ) ;
}

.button-link {
	color: #00f ;
	text-decoration: underline ;
}
 
.button-link:hover {
	cursor: pointer ;
	color: #f00 ;
}

JavaScriptのサンプル

$(function(){
	$("#modal-open").click(function(){
		//キーボード操作などにより、オーバーレイが多重起動するのを防止する
		$( this ).blur() ;	//ボタンからフォーカスを外す
		if( $( "#modal-overlay" )[0] ) return false ;		//新しくモーダルウィンドウを起動しない (防止策1)
		//if($("#modal-overlay")[0]) $("#modal-overlay").remove() ;		//現在のモーダルウィンドウを削除して新しく起動する (防止策2)

		//オーバーレイを出現させる
		$( "body" ).append( '<div id="modal-overlay"></div>' ) ;
		$( "#modal-overlay" ).fadeIn( "slow" ) ;

		//コンテンツをセンタリングする
		centeringModalSyncer() ;

		//コンテンツをフェードインする
		$( "#modal-content" ).fadeIn( "slow" ) ;

		//[#modal-overlay]、または[#modal-close]をクリックしたら…
		$( "#modal-overlay,#modal-close" ).unbind().click( function(){

			//[#modal-content]と[#modal-overlay]をフェードアウトした後に…
			$( "#modal-content,#modal-overlay" ).fadeOut( "slow" , function(){

				//[#modal-overlay]を削除する
				$('#modal-overlay').remove() ;

			} ) ;

		} ) ;

	} ) ;

	//リサイズされたら、センタリングをする関数[centeringModalSyncer()]を実行する
	$( window ).resize( centeringModalSyncer ) ;

	//センタリングを実行する関数
	function centeringModalSyncer() {

		//画面(ウィンドウ)の幅、高さを取得
		var w = $( window ).width() ;
		var h = $( window ).height() ;

		// コンテンツ(#modal-content)の幅、高さを取得
		// jQueryのバージョンによっては、引数[{margin:true}]を指定した時、不具合を起こします。
		var cw = $( "#modal-content" ).outerWidth( {margin:true} );
		var ch = $( "#modal-content" ).outerHeight( {margin:true} );
		var cw = $( "#modal-content" ).outerWidth();
		var ch = $( "#modal-content" ).outerHeight();

		//センタリングを実行する
		$( "#modal-content" ).css( {"left": ((w - cw)/2) + "px","top": ((h - ch)/2) + "px"} ) ;

	}

} ) ;

【追記】モーダルウィンドウのスクロール時に背景を固定させるには?

先日コメントにて、「モーダルウィンドウをスクロールした時に背景までスクロールされてしまうので、背景を固定するにはどうしたらよいでしょうか。」といった内容のご質問を受けましたので、追記させていただきます。

下記テキストリンクをクリックすると、モーダルウィンドウが表示されます。

ここで表示されるモーダルウィンドウでは、背景部分は固定され、モーダル内部についてはスクロール可能としています。コンテンツ内の閉じるボタン、または背景のオーバーレイをクリックすると、モーダルウィンドウを閉じます。

クリックするとモーダルウィンドウ(背景固定)を開きます。

背景固定版のサンプルコード

CSSのサンプル

#modal-content {
	width: 50% ;
	height:40%;
	margin: 0 ;
	padding: 10px 20px ;
	border: 2px solid #aaa ;
	background: #fff ;
	position: fixed ;
	display: none ;
	z-index: 2 ;
	overflow-y: scroll;
}

先ほどのCSSと異なるのは、#modal-content の部分だけとなります。

モーダル部分の高さを指定するために「height:40%;」をサンプルでは追加しています。

また、モーダル内部をスクロール可能にするため、「overflow-y: scroll;」を追加しています。

JavaScriptのサンプル

var pointY;
$(function(){
	$("#modal-open").click(function(){
		//キーボード操作などにより、オーバーレイが多重起動するのを防止する
		$( this ).blur() ;	//ボタンからフォーカスを外す
		if( $( "#modal-overlay" )[0] ) return false ;		//新しくモーダルウィンドウを起動しない (防止策1)
		//if($("#modal-overlay")[0]) $("#modal-overlay").remove() ;		//現在のモーダルウィンドウを削除して新しく起動する (防止策2)

		//背景固定
		pointY = $(window).scrollTop();
		$('body').css({
			'position': 'fixed',
			'width': '100%',
			'top': -pointY
		});

		//オーバーレイを出現させる
		$( "body" ).append( '<div id="modal-overlay"></div>' ) ;

		$( "#modal-overlay" ).fadeIn( "slow" ) ;

		//コンテンツをセンタリングする
		centeringModalSyncer() ;

		//コンテンツをフェードインする
		$( "#modal-content" ).fadeIn( "slow" ) ;

		//[#modal-overlay]、または[#modal-close]をクリックしたら…
		$( "#modal-overlay,#modal-close" ).unbind().click( function(){

			//[#modal-content]と[#modal-overlay]をフェードアウトした後に…
			$( "#modal-content,#modal-overlay" ).fadeOut( "slow" , function(){

				//[#modal-overlay]を削除する
				$('#modal-overlay').remove() ;
				
				//背景固定を解除する
				releaseScrolling();
			} ) ;

		} ) ;

	} ) ;
//背景固定解除
function releaseScrolling(){
	$('body').css({
		'position': 'relative',
		'width': '',
		'top': ''
	});
	$(window).scrollTop(pointY);
}

	//リサイズされたら、センタリングをする関数[centeringModalSyncer()]を実行する
	$( window ).resize( centeringModalSyncer ) ;

	//センタリングを実行する関数
	function centeringModalSyncer() {

		//画面(ウィンドウ)の幅、高さを取得
		var w = $( window ).width() ;
		var h = $( window ).height() ;

		// コンテンツ(#modal-content2)の幅、高さを取得
		// jQueryのバージョンによっては、引数[{margin:true}]を指定した時、不具合を起こします。
		var cw = $( "#modal-content" ).outerWidth( {margin:true} );
		var ch = $( "#modal-content" ).outerHeight( {margin:true} );
		var cw = $( "#modal-content" ).outerWidth();
		var ch = $( "#modal-content" ).outerHeight();

		//センタリングを実行する
		$( "#modal-content" ).css( {"left": ((w - cw)/2) + "px","top": ((h - ch)/2) + "px"} ) ;

	}

} ) ;

先ほどのJavaScriptに追加する部分は4か所です。

まず、背景を固定するときに指定する高さを取得し変数に格納するため「var pointY;」で変数を追加します。

次に、モーダルウィンドウ表示用のボタンをクリックしたときに、背景を固定させるため、

//背景固定
pointY = $(window).scrollTop();
$('body').css({
	'position': 'fixed',
	'width': '100%',
	'top': -pointY
});

を「$(“#modal-open”).click(function(){」以降に追加します。

「pointY = $(window).scrollTop();」では先ほど追加した変数に、現時点でのy座標を取得しています。

次に、背景部分にあたるbodyに対し、CSSを追加します。

「’top’: -pointY」を追加しておかないと、「top:0」となり、最上部へ移動してしまうので、現時点の座標にとどめておくために、「’top’: -pointY」を追加します。

これで、背景固定は完了です。

続いて、固定解除のために、オーバーレイ部分もしくは閉じるボタンをクリックしたときの処理として、「releaseScrolling();」を追加します。

記述場所は、「$(‘#modal-overlay-fixed’).remove() ;」のあとが良いでしょう。

この、「releaseScrolling();」の処理として、「$(“#modal-open”).click(function(){ ~~~ } ) ;」のあとに

//背景固定解除
function releaseScrolling(){
	$('body').css({
		'position': 'relative',
		'width': '',
		'top': ''
	});
	$(window).scrollTop(pointY);
}

を追加します。

ここで、先ほど背景を固定するためにbody要素に対して行ったCSSの記述をリセットしています。

「$(window).scrollTop(pointY);」を指定することによって、画面固定解除後も現在の位置を維持しています。

以上で、モーダルウィンドウ表示時のスクロールでも背景を固定することができます。

コメント

  1. 東原 より:

    Noith Creative Agency様

    初めまして。
    突然のご連絡で大変失礼いたします。

    この度ご連絡させていただきました、東原と申します。

    貴殿のモーダルウィンドウの作り方のサイトを拝見させていただき、
    ソースを参考にさせていただいてるのですが、ご質問がありご連絡させていただきました。

    主にスマホでモーダルウィンドウを実装したく、実際に実装はできたのですが、
    モーダルウィンドウでスクロールさせた時に背景のページもスクロールしてしまいます。

    こちらの背景を固定させるためにはサンプルのソースに何を付け加えればいいのかご教授願えれば幸いです。
    ※色々自分なりに調べてみたのですが、知識不足で分からずじまいでして。。。

    突然の連絡で長々と勝手に不躾な質問をして大変申し訳ございません。
    また、勝手なこちらの都合でソース内容や使用サイトなどお伝えできないこと、
    重ねて大変申し訳ございません。

    もしこういった質問や、問い合わせに対応していない場合は大変失礼いたしました。

    以上、何卒よろしくお願い致します。

    東原

    • NoithCA noith より:

      東原 様
      コメントありがとうございます。
      ご参考にしていただきありがとうございます。

      モーダルウィンドウのスクロール時に背景を固定する方法を追記いたしましたので、よろしければお試しください。

      今後もよろしくお願い致します。

  2. 東原 より:

    Noith Creative Agency様

    ご連絡いただきまして、ありがとうございます!

    参考にさせていただき、無事にできました。
    本当にありがとうございます。

    今後も貴殿のブログ楽しみにしております。

    それでは失礼します。

    東原

  3. Mukai より:

    サンプルの「modal.js」66~69行でセンタリング時にcwとchを2回ずつ定義されているのは何故ですか?

    • NoithCA noith より:

      お返事遅くなってしまい申し訳ございません。
      ご質問いただいてからお時間が経っておりますので、もしかすると自己解決されているかもしれませんが、念のため回答させていただきます。

      cwとchについて、
      jQueryのバージョンによっては、outerWidth();、outerHeight();それぞれの引数に{margin:true}を指定した時、不具合を起こします。

      var cw = $( “#modal-content” ).outerWidth( {margin:true} );
      var ch = $( “#modal-content” ).outerHeight( {margin:true} );

      で正しく表示される場合は特に問題ありませんが、不具合が起きる場合は代わりに

      var cw = $( “#modal-content” ).outerWidth();
      var ch = $( “#modal-content” ).outerHeight();

      を記述してください。
      なお、当ページのサンプルコードでは、
      var cw = $( “#modal-content” ).outerWidth();
      var ch = $( “#modal-content” ).outerHeight();
      を記述していないとモーダルウィンドウとしては動きますが、コンテンツ部分の幅と高さを取得できずにモーダルコンテンツが画面に見えない位置で表示されてしまいます。

  4. hoshino より:

    はじめましていつも勉強させて頂いてます!

    一つのhtml内にモーダルウィンドウのリンクが複数(1000近く)必要で
    そのリンク毎に異なる情報のモーダルウィンドウを表示したいのですが、
    (数字データなどをモーダルウィンドウ側に渡したいです)
    その場合何か方法などはございますでしょうか?

    ご存知でしたらご教示頂けますと幸いです。
    宜しくお願い致します。

    • NoithCA noith より:

      はじめまして。
      コメントありがとうございます!

      詳細がわかりませんので具体的なところはお伝えできませんが、data属性などをうまく活用すれば実現できるのではないでしょうか?

      コードなど詳細がもう少しわかれば、具体的なご提案ができるかと思いますので、必要でしたらメールかChatWorkにてご相談ください。

NoithCA

この記事がお役に立ったら
ビールをおごってくれませんか?

いいよ ヤダよ

おひねり
タイトルとURLをコピーしました