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

今回はjQueryで「モーダルウィンドウ」を作成する方法を解説します。モーダルウィンドウとは、表示中に他のウィンドウの操作を受け付けないウィンドウのことで、Webサイトにおいては一般的に、半透明のレイヤーを重ねてWebページを暗くした上に表示するウィンドウを指します。国内ではモーダルウィンドウを表示する代表的なJavaScriptライブラリーの名称から、「Lightbox(あるいはライトボックス風)ウィンドウ」と呼ばれることも多いUIです。


「モーダルウィンドウ」風の動作をするUIを作る回。画面変更時、画面遷移が主なやり方だった過去よさらば。
まずはHTMLとCSSで実現してみよう。


・・・


てか、サンプルのコードだと全然レイアウトが違うんだけど。。どーなってんのコレ?
ソースみたらCSSの指定が全然足りてねぇよ〜。困るよ〜。

<html>
  <head>
    <style>
html,body{
    margin:0;
    padding:0;
    height:100%;
}
/* サンプルコードだと以下の指定がない。。 */
h1{
	margin:20px 50px;
	font-size:large;
	border-left:10px solid #7BAEB5;
	border-bottom:1px solid #7BAEB5;
	padding:10px;
	width:600px;
}
ul{
	width:700px;
}
ul li{
	float:left;
	list-style-type:none;
}
ul li img{
	border:0;
	margin:10px;
}

/* サンプルコードだとこうなってるんだけど・・・ */
/*
#glayLayer{
    position:fixed;
    top:0;
    left:0;
    height:100%;
    width:100%;
    background:black;
    opacity: 0.60;
    filter:alpha(opacity=60);
}
*/
/* 実際に表示されるページのソースはこうなってる。ひどいなぁ。 */
div#glayLayer{
    position:fixed;
    left:0;
    top:0;
    height:100%;
    width:100%;
    background:black;
    filter:alpha(opacity=60);
    opacity: 0.60;
}


#overLayer{
    position: fixed;
    top:50%;
    left:50%;
    margin-top:-244px;
    margin-left:-325px;
}
    </style>
    <script type="text/javascript" src="http://www.google.com/jsapi"></script>
    <script type="text/javascript">google.load("jquery", "1.3.2");</script>
    <script type="text/javascript">
    </script>
  </head>
  <body>
    <h1>jQueryを利用したモーダルウィンドウの作成</h1>
    <ul>
      <li>
	<a href="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo1.jpg" class="modal">
	  <img src="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo1_thum.jpg" alt="シャンデリア" />
        </a>
      </li>
      <li>
	<a href="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo2.jpg" class="modal">
	  <img src="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo2_thum.jpg" alt="バラ" />
        </a>
      </li>
      <li>
	<a href="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo3.jpg" class="modal">
	  <img src="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo3_thum.jpg" alt="海" />
        </a>
      </li>
      <li>
	<a href="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo4.jpg" class="modal">
	  <img src="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo4_thum.jpg" alt="門" />
        </a>
      </li>
      <li>
	<a href="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo5.jpg" class="modal">
	  <img src="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo5_thum.jpg" alt="海" />
        </a>
      </li>
      <li>
	<a href="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo6.jpg" class="modal">
	  <img src="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo6_thum.jpg" alt="あじさい" />
        </a>
      </li>
      <li>
	<a href="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo7.jpg" class="modal">
	  <img src="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo7_thum.jpg" alt="空" />
        </a>
      </li>
      <li>
	<a href="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo8.jpg" class="modal">
	  <img src="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo8_thum.jpg" alt="建物" />
        </a>
      </li>
    </ul>
    <div id="glayLayer"></div>
    <div id="overLayer"><img src="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo5.jpg" /></div>
  </body>
</html>

次にjQueryを使って動作を定義しちゃう。と、その前にやることが2つ。
id="glayLayer"とid="overLayer"のタグを消去し、CSSの該当するスタイルに、初期非表示になるようにdisplay:none;を追加する。(ま、タグが存在しないって時点で表示されないわけだが。)

<html>
  <head>
    <style>
html,body{
    margin:0;
    padding:0;
    height:100%;
}
h1{
	margin:20px 50px;
	font-size:large;
	border-left:10px solid #7BAEB5;
	border-bottom:1px solid #7BAEB5;
	padding:10px;
	width:600px;
}
ul{
	width:700px;
}
ul li{
	float:left;
	list-style-type:none;
}
ul li img{
	border:0;
	margin:10px;
}
div#glayLayer{
    display:none; /* 初期状態で非表示になるようにする。 */
    position:fixed;
    left:0;
    top:0;
    height:100%;
    width:100%;
    background:black;
    filter:alpha(opacity=60);
    opacity: 0.60;
}
#overLayer{
    display:none; /* 初期状態で非表示になるようにする。 */
    position: fixed;
    top:50%;
    left:50%;
    margin-top:-244px;
    margin-left:-325px;
}
    </style>
    <script type="text/javascript" src="http://www.google.com/jsapi"></script>
    <script type="text/javascript">google.load("jquery", "1.3.2");</script>
    <script type="text/javascript">
    $(function(){
      //glayLayerとoverLayerのdivタグを追加。
      //追加した時点でCSSが適用されるのでこの2つのタグは非表示の状態。
      $("body").append("<div id='glayLayer'></div><div id='overLayer'></div>")
    
      //glayLayerがクリックされると、このタグとoverLayerのタグが非表示になる。
      $("#glayLayer").click(function(){
        $(this).hide()
        $("#overLayer").hide()
      })
    
      //サムネイルのイメージをクリックしたら、
      $("a.modal").click(function(){
        //画面全体がグレーアウトされて、
        $("#glayLayer").show()
        //ど真ん中にクリックしたサムネイルイメージの真打ちが表示される。
        $("#overLayer").show().html("<img src='"+$(this).attr("href")+"' />")
        //で、aタグをクリックした挙動なので、最後にリクエストが飛ばないようにfalseを返却。
        return false;
      })
    
      //クソッタレIEの為のロジック。説明は書かない。この勉強は俺の趣味だから。
      //業務で必要になったら書いてやんよ。
      if($.browser.msie && $.browser.version<7){
        $(window).scroll(function(){
          $("#glayLayer").css('top',$(document).scrollTop())
          $("#overLayer").css('top',($(document).scrollTop()+$(window).height()/2) +"px")
        })
      }
    })
    </script>
  </head>
  <body>
    <h1>jQueryを利用したモーダルウィンドウの作成</h1>
    <ul>
      <li>
	<a href="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo1.jpg" class="modal">
	  <img src="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo1_thum.jpg" alt="シャンデリア" />
        </a>
      </li>
      <li>
	<a href="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo2.jpg" class="modal">
	  <img src="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo2_thum.jpg" alt="バラ" />
        </a>
      </li>
      <li>
	<a href="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo3.jpg" class="modal">
	  <img src="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo3_thum.jpg" alt="海" />
        </a>
      </li>
      <li>
	<a href="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo4.jpg" class="modal">
	  <img src="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo4_thum.jpg" alt="門" />
        </a>
      </li>
      <li>
	<a href="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo5.jpg" class="modal">
	  <img src="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo5_thum.jpg" alt="海" />
        </a>
      </li>
      <li>
	<a href="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo6.jpg" class="modal">
	  <img src="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo6_thum.jpg" alt="あじさい" />
        </a>
      </li>
      <li>
	<a href="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo7.jpg" class="modal">
	  <img src="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo7_thum.jpg" alt="空" />
        </a>
      </li>
      <li>
	<a href="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo8.jpg" class="modal">
	  <img src="http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/photo8_thum.jpg" alt="建物" />
        </a>
      </li>
    </ul>
  </body>
</html>

お〜、動くじゃん。ちょっと味気ねぇけど。さて、ちょっとイメージのURLが冗長なのですっきりさせよう。

<html>
  <head>
    <style>
html,body{
    margin:0;
    padding:0;
    height:100%;
}
h1{
	margin:20px 50px;
	font-size:large;
	border-left:10px solid #7BAEB5;
	border-bottom:1px solid #7BAEB5;
	padding:10px;
	width:600px;
}
ul{
	width:700px;
}
ul li{
	float:left;
	list-style-type:none;
}
ul li img{
	border:0;
	margin:10px;
}
div#glayLayer{
    display:none; /* 初期状態で非表示になるようにする。 */
    position:fixed;
    left:0;
    top:0;
    height:100%;
    width:100%;
    background:black;
    filter:alpha(opacity=60);
    opacity: 0.60;
}
#overLayer{
    display:none; /* 初期状態で非表示になるようにする。 */
    position: fixed;
    top:50%;
    left:50%;
    margin-top:-244px;
    margin-left:-325px;
}
    </style>
    <script type="text/javascript" src="http://www.google.com/jsapi"></script>
    <script type="text/javascript">google.load("jquery", "1.3.2");</script>
    <script type="text/javascript">
    $(function(){
      //初期化処理
      var baseUrl = "http://editors.ascii.jp/m-kobashigawa/jquery_sample/020/images/"
      //aタグを取り出して、
      $("a.modal").each(function(){
        //idから取得した画像ファイルの一部の名前を使って
        var url = baseUrl + $(this).attr("id")
        //真打ち画像とサムネイル画像のURLを適切にタグにセットする。
        $(this).attr("href", url + ".jpg")
        $(">img", this).attr("src", url + "_thum.jpg")
      })

      //動的に生成していたglayLayerとoverLayerは静的にタグ定義しておいてみた。
      //Firefox上では何の問題もなさげだが、IEだと影響があるんだろうか。
      //そもそも一つ前のサンプルで、わざわざ動的にこれらのタグを生成しようとしていたのか不明なんだよな〜。
    
      $("#glayLayer").click(function(){
        //閉じるときの動作をfadeOutにしてみた。
        //まずはoverLayerをfadeOutし、その後0.5秒してからglayLayerを非表示にする感じ。
        $("#overLayer").fadeOut("slow")
        var target = $(this)
        setTimeout(function(){
          target.hide()
        },500)
      })
    
      $("a.modal").click(function(){
        //表示するときの動作をfadeInにしてみた。
        //まずはglayLayerを表示し、その後0.5秒してからglayLayerをfadeInする感じ。
        $("#glayLayer").show()
        var url = $(this).attr("href")
        setTimeout(function(){
          $("#overLayer").fadeIn("slow")
                         .html("<img src='"+url+"' />")
        },500)
        return false;
      })
    
      if($.browser.msie && $.browser.version<7){
        $(window).scroll(function(){
          $("#glayLayer").css('top',$(document).scrollTop())
          $("#overLayer").css('top',($(document).scrollTop()+$(window).height()/2) +"px")
        })
      }
    })
    </script>
  </head>
  <body>
    <h1>jQueryを利用したモーダルウィンドウの作成</h1>
    <ul>
      <li><a id="photo1" class="modal"><img alt="シャンデリア" /></a></li>
      <li><a id="photo2" class="modal"><img alt="バラ" /></a></li>
      <li><a id="photo3" class="modal"><img alt="海" /></a></li>
      <li><a id="photo4" class="modal"><img alt="門" /></a></li>
      <li><a id="photo5" class="modal"><img alt="海" /></a></li>
      <li><a id="photo6" class="modal"><img alt="あじさい" /></a></li>
      <li><a id="photo7" class="modal"><img alt="空" /></a></li>
      <li><a id="photo8" class="modal"><img alt="建物" /></a></li>
    </ul>
    <div id='glayLayer'></div>
    <div id='overLayer'></div>
  </body>
</html>

だいぶすっきりしたなぁ。てかタグ部分は冗長にするとコードが見にくくなるね。俺はjavascriptのコードで初期化まで書いちゃった方がわかりやすくて好きだなぁ。