モーダルウィンドウを実装してみよう
※2015.1.26 誤字脱字、説明を修正いたしました。
最近モーダルウィンドウ(ポップアップウィンドウ?)の実装ばっかりやっているココエです。頭の中が常にモーダルです困りました。
なので、モーダルウィンドウの実装について書いていきたいと思います。
モーダルウィンドウなんてライブラリ使えばいいじゃん?
ごもっともです!!!!!!
ごもっともなのですが、ライブラリを使っていると・・・
- 容量がやたら重かったり・・・
- PCとスマホ両方の対応がされていなかったり・・・
- ライブラリをカスタマイズしなければいけない機能がでてきたけど、使い方はさておき、修正なんて出来ないよ・・・
なんてことが・・・ありませんか?
・・・あれ?・・ない?(汗
じゃあ、じゃあ・・・
モーダルウィンドウの実装が、自前でできちゃったりすると、ちょっと便利だよね?
なんて思ったことはどうでしょう?
きっと、そんなニーズがあると信じて・・・信じて!
モーダルウィンドウの実装方法について、書きつらねていきたいと思いますw
目次
目次
- 基本形
-
応用編-Step1(後日公開予定)
- スクロールしている場合は、表示中のウィンドウの位置にモーダルウィンドウが表示されるようにする。
- ページ内に、モーダルを表示するためのトリガを複数設定する。
-
応用編-Step2(後日公開予定)
- モーダルウィンドウの高さ(+上下余白値+スクロールY値)が、ドキュメントの高さを超えた場合の処理。
- ページ内に、複数のトリガを設定し、トリガの内容に応じたモーダルウィンドウを表示する。
-
応用編-Step3(後日公開予定)
- モーダルウィンドウ下のレイヤーをクリックしたら、モーダルウィンドウを閉じる。
- フェードインで表示、フェードアウト閉じる。
-
応用編-Step4(後日公開予定)
- モーダルウィンドウ内に、テンプレートを使って表示したい。(一部だけ動的に書き換えてほしい)
- モーダルウィンドウを閉じずに、モーダルウィンドウ内のコンテンツを変える。
補足
- ソースは https://github.com/kokoe/modal/ こちらにあげております。
- 対象ブラウザは、PC:IE9以降、スマホiOS5, Android4以降を対象としています。
・・・が、テストしきれていない部分もありますため、動作保障はいたしかねます。動作不良がありましたら何卒ご容赦を。。ソースはあくまで実装方法の参考として見ていただければと思います。
基本形
まず最初に、今回の「基本形」を実装した完成形をお見せします。
モーダルウィンドウ基本形 デモ
基本的なモーダルウィンドウの機能(画面内に表示して、「閉じる」を押したら閉じる)は、実装できているのではないかと思います。
スタイル・デザインはまったく入っていませんが、逆に言うと、自分でスタイルをいれてあげれば、好きなようにデザインが適用できちゃいますよ~。
HTML/CSSの準備
まず、基本となるHTML/CSSを準備しましょう。
HTML
以下のようなHTMLを用意します。
https://github.com/kokoe/modal/blob/master/src/base/index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
[sourcecode lang="html"] <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>Modal Window</title> <!-- スマートフォンサイトなら、この記述をいれましょう --> <meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0"> <!-- reset.css --> <link rel="stylesheet" type="text/css" href="//yui.yahooapis.com/3.18.1/build/cssreset/cssreset-min.css"> <!-- モーダルウィンドウを実装する際の基本CSS --> <link rel="stylesheet" type="text/css" href="../css/modal.css"> </head> <body> <div id="wrap"> <!-- #contents内に、ページのコーディングをしていきます --> <div id="contents"> <h1>モーダルウィンドウ</h1> <p>基本形</p> <br> <a id="openModal" href="javascript:void(0)">クリックするとモーダルが開くよ</a> </div> <!-- #contentsの同階層に、モーダルウィンドウの記述をしていきます .modalBaseLayer -> モーダルウィンドウ下の黒いレイヤー層 .modal -> モーダルウィンドウ --> <div id="modalBaseLayer" class="modalBaseLayer"> <div id="modal" class="modal"> モーダルウィンドウが開きましたね。 <a href="javascript:void(0)" id="closeModal">閉じる</a> </div> <!-- /#modalBaseLayer --></div> <!-- /#wrap --></div> <script src="./modal.js"></script> </body> </html> [/sourcecode] |
※reset.cssは、上記の例ではyuiさんのを使用させていただいておりますが、ご自身のお好みのreset.cssを指定ください。
※modal.cssのファイルパスは、後述するmodal.cssのファイルの保存場所を指定してください。
以下のような構造になれば、上記の通りでなくてもOKです。
※この構造を変えると正しく動きませんので、ご注意ください。(後述するスタイルの設定に関連するため。)
1 2 3 4 5 6 7 |
html ├ head └ body └ #wrap ├ #contents - ページコーディング部分 └ #modalBaseLayer.modalBaseLayer - モーダルウィンドウ・ベースレイヤ └ #modal.modal - モーダルウィンドウ |
なお、応用編以降では、モーダルウィンドウの数が増えます。
そのため、エレメント選択をIDからクラスに変えるものも発生する予定です。(上記ではIDで指定)
また、モーダルウィンドウが増えた場合は、以下のような構造になる予定です。
1 2 3 4 5 6 7 8 9 |
html ├ head └ body └ #wrap ├ #contents - ページコーディング部分 ├ #modalBaseLayer1.modalBaseLayer - モーダルウィンドウ1・ベースレイヤ └ .modal - モーダルウィンドウ1 └ #modalBaseLayer2.modalBaseLayer - モーダルウィンドウ2・ベースレイヤ └ .modal - モーダルウィンドウ2 |
CSS
以下のCSSを用意します。(記述が面倒な方はダウンロードしちゃいましょう。)
https://github.com/kokoe/modal/blob/master/src/css/modal.css
CSSのPoint
html, body {height: 100%} #wrap {min-height: 100%}
画面(というかドキュメント)いっぱいに、モーダルウィンドウのベースレイヤを配置するためにはどうしたらよいでしょう?
Javascriptでドキュメントの幅・高さを取得して、モーダルウィンドウのベースレイヤにstyle属性でwidth, height値をセットして・・・
なんてことはする必要ありません。
- html, body要素に対して、height: 100%を設定。
- body直下の#wrapに対して、min-height: 100%を設定。
- #wrap直下のモーダルウィンドウのベースレイヤ(.modalBaseLayer)に、position:absolute, top:0, left:0, right:0, bottom:0 を指定
これだけで、ドキュメントの幅・高さピッタリにモーダルウィンドウのベースレイヤが配置できるのです。
モーダルウィンドウは、大概の場合ページロード時に非表示にしておくケースが多いです。
そのため、CSSでベースレイヤーを非表示にしておく必要がありますが、その際利用するCSSプロパティと値は、visibility: hiddenを使います。
一見、display:noneとしそうですが、.modalBaseLayerにposition:absoluteを指定しているからこそ、visibilityプロパティを使用するとよいです。
では、visibilityプロパティを利用すると、何がうれしいか?・・・というと
visibility: hiddenで、該当の要素が表示されていなくても、Javascriptで高さを取得することが出来ます。
※display:noneが指定されている要素は、Javascriptで高さが取得できないのです。(0が返ってきます)
モーダルウィンドウの実装は、モーダルウィンドウの高さを取得して、表示位置を決めたり、ドキュメントサイズの調整をしたり、という作業が発生するため、非表示でも高さが取得できるということは重要なメリットになります。
Javascriptの準備
HTML/CSSの準備ができましたら、モーダルウィンドウを表示したり、非表示にするJavascriptの処理をくんでいきましょう。
以下のJavascriptソースが処理内容になります。
https://github.com/kokoe/modal/blob/master/src/base/modal.js
詳しくは、ソースのコメントを参照いただければと思いますので、
ここでは、ざっくりと全体の処理を説明します。
- 「クリックするとモーダルが開くよ」のリンクに、イベントリスナ(onclick)を設定。bindOpenModal();
- 1が実行されたら、モーダルウィンドウ・ベースレイヤのstyle属性・visibilityプロパティ値をvisibleにする。
- 「閉じる」のリンクに、イベントリスナ(onclick)を設定。bindCloseModal();
- 3が実行されたら、モーダルウィンドウ・ベースレイヤのstyle属性・visibilityプロパティ値をhiddenにする。
はい、これだけです!!!基本的な実装なら簡単でしょ?
モーダルウィンドウのベースレイヤの配置処理をHTML/CSSで実装することで、Javascriptの実装はとてもシンプルになります。
問題点
・・・ただ、これだけの実装だと、こんなことが起こります。
- スクロールしている状態で、モーダルウィンドウを表示すると、画面内にモーダルウィンドウが表れません!
- モーダルウィンドウの高さ(+上下余白値+スクロールY値)が、ドキュメントの高さを超えた場合、モーダルウィンドウが切れて表示されてしまいます!
これでは、困ってしまいますね・・・さらに
- モーダルウィンドウが複数ある場合はどうしたらいいの?
- モーダルウィンドウを表示するためのリンク(トリガ)を複数設置したんだけど?
といった要望に答えられないソースになっています。
・・・というわけで、応用編からは上記問題点を解決する実装をしていきます。
※・・・と言いつつも、実は実装は完了していて、GitHubにあがっているので、興味がある方はソース覗いてみてください。
さて、それではみなさま、よいお年を~~(ネンマツ!ネンマツ!!