初心者でも分かる!モーダルウィンドウの作り方

初心者でも分かる!モーダルウィンドウの作り方

コンテンツを浮かび上がるようにポップアップ表示させるモーダルウィンドウ。ヘルプやアラートなど、ちょっとしたメッセージを表示するのにスペースを取らないから重宝しますよね。今回はこのモーダルウィンドウの作り方をJavaScript初心者向けに解説します。

サンプルデモ

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

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

サンプルデモを見る

制作方法

コンテンツの作成

まずはモーダルウィンドウで表示されるコンテンツを作成していきます。後ほどいくらでも変更することが可能なので、現段階ではこだわる必要はありません。サンプルを下記に用意しました。

サンプル

モーダルウィンドウを終了させるためのボタンとして、「閉じる」というリンクテキストを用意します。全体を囲むdiv要素とボタンには、それぞれ、id属性値を付けておきましょう。display:noneで初期状態では非表示にしておくことを忘れないで下さいね。

HTML

<div id="modal-content">
	<p>「閉じる」か「背景」をクリックするとモーダルウィンドウを終了します。</p>
	<p><a id="modal-close" class="button-link">閉じる</a></p>
</div>

CSS

#modal-content{
	width:50%;
	margin:1.5em auto 0;
	padding:10px 20px;
	border:2px solid #aaa;
	background:#fff;
	z-index:2;
}

.modal-p{
	margin-top:1em;
}

.modal-p:first-child{
	margin-top:0;
}

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

手前に表示させる

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

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

CSS

#modal-content{
	/*追加分*/
	z-index:2;
}

手前に表示させる

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

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

CSS

#modal-content{
	/*追加分*/
	position:fixed;
}

オーバーレイの作成

続いて、オーバーレイの部分を作成していきましょう。モーダルウィンドウを表示させると、よく背景が黒や白の半透明になって、その部分をクリックするとウィンドウを閉じたりできますよね。あの膜みたいな部分のことです。

サンプル

下記はサンプルです。後ほどjQueryで操作するため、id属性値を指定しておきます。なお、このHTMLはJavaScriptで動的に生成するため、HTML上に用意しておく必要はありません。後ほど、このHTMLを呼び出すということを意識しておいて下さい。

HTML

<div id="modal-overlay"></div>

CSS

#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);
}

位置固定する

オーバーレイのイメージ
オーバーレイのイメージ

今回のオーバーレイは、ページ全体ではなく画面全体を覆います。そのため、width:100%height:120%を指定し、さらにposition:fixedで位置を固定しておきましょう。図のように、スクロールしてもずっと付いてくるのをイメージして下さい。これで、あたかもページ全体が覆われているかのようになりますね。

CSS

#modal-overlay{
	/*追加分*/
	width:100%;
	height:120%;
	position:fixed;
	top:0;
	left:0;
}

スマホ対策としての120%

iPhoneのナビバー
iPhoneのナビバー

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

背景を半透明にする

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

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

ここからいよいよ、JavaScriptを取り扱っていきます。jQueryを利用するので、あらかじめ読み込んでおきましょう。

ボタンを用意する

モーダルウィンドウを呼び出すためのボタンを用意しておきましょう。下記はid属性値を付けたテキストリンクのサンプルです。

HTML

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

クリックイベントの設定

まずはボタンをクリックした時にモーダルウィンドウを表示させるイベントを設定しましょう。クリックイベントは下記の通り指定します。

CSS

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

オーバーレイを表示する

ボタンをクリックした時に、まずはオーバーレイ(id: modal-overlay)を表示させましょう。先ほど作成したオーバーレイのHTMLコードは あらかじめHTML上に用意されていないため、jQueryで動的に生成する必要がありましたね。具体的には次のように行ないます。キーボード操作などで、モーダルウィンドウが多重起動してしまうのを防止しています。

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により、じんわりと表示させています。

コンテンツを表示する

続いて、メインになるコンテンツ部分を出現させましょう。「出現のさせ方」は、オーバーレイと同じく、フェードインさせるだけです。

jQuery

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

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

ここが今回、頭を使うところです。コンテンツを画面の真ん中に表示させるにはどうすればいいかを考えてみましょう。position:fixedtop(画面上部から何ピクセル離れているか)とleft(画面左部から何ピクセル離れているか)の値を、上手く設定します。

例えば、画面幅が1000pxあって、コンテンツ幅が200pxある場合、真ん中に持ってくるには、left(片側の余白の値)に400pxを設定します。左端から400px離せばいいというわけです。縦幅も同じですね。「片側の余白」は次の計算で求めることができます。

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

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

jQuery

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

	//画面(ウィンドウ)の幅を取得し、変数[w]に格納
	var w = $(window).width();

	//画面(ウィンドウ)の高さを取得し、変数[h]に格納
	var h = $(window).height();

	//コンテンツ(#modal-content)の幅を取得し、変数[cw]に格納
	var cw = $("#modal-content").outerWidth({margin:true});

	//コンテンツ(#modal-content)の高さを取得し、変数[ch]に格納
	var ch = $("#modal-content").outerHeight({margin:true});

	//コンテンツ(#modal-content)を真ん中に配置するのに、左端から何ピクセル離せばいいか?を計算して、変数[pxleft]に格納
	var pxleft = ((w - cw)/2);

	//コンテンツ(#modal-content)を真ん中に配置するのに、上部から何ピクセル離せばいいか?を計算して、変数[pxtop]に格納
	var pxtop = ((h - ch)/2);

	//[#modal-content]のCSSに[left]の値(pxleft)を設定
	$("#modal-content").css({"left": pxleft + "px"});

	//[#modal-content]のCSSに[top]の値(pxtop)を設定
	$("#modal-content").css({"top": pxtop + "px"});

}

この処理で使用した関数についての詳細は、下記ページをご参考下さい。

$(window).height()の不具合

オーバーレイを作成する時にも触れましたが、スマホ(iPhone)だと、$(window).height()で取得できる高さは「上下のナビバーのスペースだけ縮んだ分の高さ」です。

また、それとは別に、$(window).height()で取得できる高さは、微妙に少ない方向にズレることがあるそうです。そのため、正確な高さを取得したい場合は、jQueryではなく、下記のようにJavaScript本来の記述で取得するのをお勧めします。

JavaScript

//画面(ウィンドウ)の高さを取得し、変数[h]に格納
var h = window.innerHeight;

今回のモーダルウィンドウにおいては、特に大きな影響がないため、あえて$(window).height()をそのまま利用しています。むしろ、取得できるウィンドウの高さが少なくなる分、少しだけウィンドウがセンターより上に来るので見やすいなーとか思ってます。

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

いよいよ仕上げです。モーダルウィンドウを終了させるクリックイベントを設定しましょう。

クリックイベントの設定

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

jQuery

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

click()の直前にあるunbind()は、対象の要素にそれまで設定されていたイベントをクリアする命令です。ここでは、おまじないのようなものだと思って下さい。

フェードアウトさせる

オーバーレイとコンテンツをフェードアウトで非表示にした後に、HTML上からオーバーレイのHTMLを削除します。それには次の通り、命令しましょう。fadeOut()の第2引数に関数を指定することで、その関数がフェードアウトしたタイミングで実行されます。remove()は対象の要素をHTML上から削除する命令です。

jQuery

//[#modal-overlay]と[#modal-close]をフェードアウトする
$("#modal-content,#modal-overlay").fadeOut("slow",function(){
	//フェードアウト後、[#modal-overlay]をHTML(DOM)上から削除
	$("#modal-overlay").remove();
});

応用編

モーダルウィンドウの基本的な作成方法は分かったと思います。この章では、ここまでを踏まえて、モーダルウィンドウを色々とカスタマイズしていく方法を紹介します。

リサイズに対応する

ここまでのプログラムでは、モーダルウィンドウを表示させた後にウィンドウを広げると、センタリングが崩れてしまいます。ブラウジングをしていてウィンドウの幅を変更する人はそうはいないので、無視しても問題ないとは思いますが、「どうしても気になる…」という場合は「リサイズが起きたらセンタリングする」という処理を加えましょう。

リサイズイベントの設定

リサイズを条件に、先ほど作成したセンタリングの関数を実行すればいいですね。それには次の通り、記述します。この1行を加えるだけで、リサイズに対応することが可能です。

jQuery

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

複数設置する

制作方法では、モーダルウィンドウのコンテンツや、モーダルウィンドウを開くためのボタン(リンクテキスト)にID属性値を設定してきました。これでは、1ページにつき、1つのモーダルウィンドウしか設置できません。これを、例えば、クラス属性値に変更することで、1ページ内に複数種類のモーダルウィンドウを設置することが可能になります。下記はそのサンプルデモです。

サンプルデモ

複数のモーダルウィンドウ
複数のモーダルウィンドウ

下記は1ページ内に複数のモーダルウィンドウを設置するサンプルデモです。それぞれのリンクテキストに応じて、指定されたモーダルウィンドウが開きます。

サンプルデモを見る

仕組みの説明

このモーダルウィンドウは、ダウンロードコーナーで配布しているので、興味のある人は、ぜひ、お使い下さい。仕組みを簡単に説明すると、これまで通りに、開いた時に表示させたいモーダルウィンドウのコンテンツを用意し、これをdisplay: none;で非表示状態にしておきます。1つ1つのコンテンツには、一意のID属性値を設定しておくのを忘れないで下さい。

HTML

<div id="modal-01">1つ目のモーダルウィンドウの中身</div>
<div id="modal-02">2つ目のモーダルウィンドウの中身</div>
<div id="modal-03">3つ目のモーダルウィンドウの中身</div>

そして、これらのモーダルウィンドウを開くボタンとなる要素には、特定のクラス属性値(下記サンプルではmodal-syncer)を設定しておいて下さい。ここで指定したクラス属性値を持つ要素全てに、クリックイベントを設置する処理を行なうことになります。そして、複数版ならではとして、それぞれのボタン要素に、data-targetという属性値を付けて、その値には、開くコンテンツのID名を指定しておきます。

HTML

<a class="modal-syncer" data-target="modal-01">1つ目のモーダルウィンドウを開く</a>
<a class="modal-syncer" data-target="modal-02">2つ目のモーダルウィンドウを開く</a>
<a class="modal-syncer" data-target="modal-03">3つ目のモーダルウィンドウを開く</a>

それぞれのボタン要素をクリックした時に、data-targetの値を参照することによって、その時に開くモーダルウィンドウのコンテンツが決定するという仕組みです。このようにして、1ページに複数種類のモーダルウィンドウを設置することが可能となります。

スクロール位置を維持する

モーダルウィンドウを開いた時と閉じた時で、スクロール位置がズレてしまうと、利用者が混乱してしまいます。それを防ぐには、モーダルウィンドウを開いた時の位置を記憶しておき、閉じた直後に、その位置まで強制的に移動させてあげましょう。開く時と閉じた直後に、それぞれ、処理を加えて下さい。ここでは、スクロール位置は、グローバル変数に記録しておくことにします。

JavaScript

//グローバル変数 (関数外)
sX_syncerModal = 0 ;
sY_syncerModal = 0 ;

JavaScript

//スクロール位置を記録
var dElm = document.documentElement , dBody = document.body;
sX_syncerModal = dElm.scrollLeft || dBody.scrollLeft;	//現在位置のX座標
sY_syncerModal = dElm.scrollTop || dBody.scrollTop;		//現在位置のY座標

JavaScript

//スクロール位置を移動
window.scrollTo( sX_syncerModal , sY_syncerModal );

サンプルデモ

スクロール位置を記録する
スクロール位置を記録する

さて、どのように動作するかを確認してみて下さいね。

サンプルデモを見る

ダウンロード

大変、お疲れ様でした!今回解説したプログラムのコードをまとめたものが下記です。確認用にお使い下さい。全てのファイルを同一ディレクトリに設置し、modal.htmlにアクセスして下さい。

ファイル一覧

SYNCER00063
modal.html Download
modal.js Download
modal.css Download
modal-multi.html Download
modal-multi.js Download
modal-multi.css Download
modal-keep-position.html Download
modal-keep-position.js Download
modal-keep-position.css Download

ファイル名をクリックすると内容を確認できます。「Download Zip」をクリックするとファイル一式をダウンロードできます。

Download Zip