モーダルウィンドウを実装してみよう(応用編) ウィンドウ内表示対応
モーダルウィンドウを実装してみよう、の記事の続きです。
前回の記事では基本形の実装を紹介しました。今回は以下の実装について説明していきたいと思います。
- ページ内に、モーダルを表示するためのトリガを複数設定する。
- スクロールしている場合は、表示中のウィンドウの位置にモーダルウィンドウが表示されるようにする。
デモ
まず最初に、今回の「応用編Step1」を実装した完成形をお見せします。
ソースは https://github.com/kokoe/modal/ こちらにあげております。
スクロールをした状態でモーダルウィンドウを表示しても、ページ内にモーダルウィンドウがちゃんと表示されていることがわかります。
また、トリガ(「クリックするとモーダルが開くよ」)のリンクが、ページ内に2つあり、どちらのリンクもクリックした際、モーダルウィンドウがきちんと表示されています。
HTML
基本構造は、基本形と変わりません。
つきましては、以下URLからindex.htmlをダウンロードして上書きしていただくとよいかと思います。
https://github.com/kokoe/modal/blob/master/src/step1/index.html
トリガのエレメント選択をIDからクラス指定へ
前回は、以下のようにIDを指定してエレメントを選択していましたが、今回はトリガが2つになりますので、エレメントはクラスで選択するように変更します。
※Javascriptの処理になりますが、.openModalを指定しているエレメントをすべて取得し、各エレメントに対してイベントハンドラ(onclick)を指定していくように処理を変更するため。
1 2 3 4 |
[sourcecode lang="diff"] - <a id="openModal" href="javascript:void(0)">クリックするとモーダルが開くよ</a> + <a class="openModal" href="javascript:void(0)">クリックするとモーダルが開くよ</a><br> [/sourcecode] |
Javascript
まず、複数トリガの設定をします。
ページ内に、モーダルを表示するためのトリガを複数設定する。
エレメントの指定を、以下のように変更します。
1 2 3 4 |
[sourcecode lang="diff"] - var openTrigger = document.getElementById('openModal'); + var openTriggers = document.querySelectorAll('#wrap .openModal') [/sourcecode] |
これで、変数openTriggersには、#wrap内の.openModalのエレメントすべてが格納(参照)されました。
次に、bindOpenModal関数(トリガのリンクをクリックした際に実行される処理)に変更を加えます。
前回のソースでは、イベントリスナの対象エレメントが#openModalに固定されていましたが、引数に対象エレメントを指定できるように修正します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[sourcecode lang="diff"] /** * 「クリックするとモーダルが開くよ」をクリックしたときの処理 */ - function bindOpenModal() { + function bindOpenModal(openTrigger) { openTrigger.addEventListener('click', function(event) { // デフォルトのイベント(ここではa要素のイベント)をキャンセル event.preventDefault(); // モーダルを表示 showModal(); }, false); } [/sourcecode] |
次に、先ほど修正したbindOpenModalとopenTriggerを使って、各トリガにイベントリスナを設定してみます。
1 2 3 4 5 6 |
[sourcecode lang="javascript"] for (var i = 0, len = openTriggers.length; i < len; i++) { // モーダルを開くためのイベントリスナを設定 bindOpenModal(openTriggers[i]); } [/sourcecode] |
これで、複数トリガ設定については修正完了です。2つのリンク、どちらをクリックしてもモーダルウィンドウが表示されるようになったかと思います。
スクロールしている場合は、表示中のウィンドウの位置にモーダルウィンドウが表示されるようにする。
次に、上記タイトルの実装をしていきます。
まずは、上記タイトルの機能を実装せずに、スクロールをした状態で、モーダルウィンドウがどのように表示されるか見て見ましょう。
画面内にモーダルウィンドウが表示がされていないことがわかります。
まず、なぜ画面内にモーダルウィンドウが表示されないかの説明になりますが、モーダルウィンドウは、ドキュメント(正確には、.modalBaseLayer)を基準として、top:10pxの位置で表示しており、画面に対してtop:10pxの位置で表示させているわけではないことが原因になります。
※以下、HTML/CSSの構造参照。
1 2 3 4 |
■HTML構造 #wrap └ .modalBaseLayer └ .modal |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
[sourcecode lang="css"] #wrap { posision: relative; } /* モーダルウィンドウ・ベースレイヤ */ .modalBaseLayer { posision: absolute; top: 0; } /* モーダルウィンドウ */ .modal { posision: absolute; top: 10px } [/sourcecode] |
では、画面に対してtop:10pxの位置で表示させるにはどうしたらよいか?
画面に対してtop:10pxの位置で表示させるということは、つまり、以下の図のように、モーダルウィンドウのtop値を、「スクロールY値」+「余白(top:10px)」に変えればよい、ということになります。
それでは、実装してみましょう。
まず、余白値を定義します。(.modalのtop値を動的にとってくるのが理想ですが、説明が複雑になるので今回は10px固定でいきます。)
1 2 3 4 |
[sourcecode lang="diff"] + // デフォルトの余白値 + var defaultMargin = 10; [/sourcecode] |
スクロールY値がとれなければ話が始まりません。スクロールY値を返す関数を追加します。
1 2 3 4 5 6 7 8 9 |
[sourcecode lang="diff"] + /** + * window.scrollYを返す + * https://developer.mozilla.org/ja/docs/Web/API/window.scrollY + */ + function getScrollY() { + return (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop; + } [/sourcecode] |
モーダルウィンドウの、style属性・topプロパティに、「スクロールY値」+「余白(top:10px)」をセットする関数を追加します。(style属性としてセットする。)
1 2 3 4 5 6 7 8 9 |
[sourcecode lang="diff"] + /** + * モーダルウィンドウのTOP値に、スクロールY値を加算した値をセットする + */ + function setModalTop() { + // スクロールY値を加算した値をセットする + modal.style.top = defaultMargin + getScrollY() + 'px'; + } [/sourcecode] |
一応、style属性・topプロパティをクリアする関数も作ります。
1 2 3 4 5 6 7 8 9 10 |
[sourcecode lang="diff"] + /** + * モーダルウィンドウのTOP値をクリアする + * 表示する度にtop値指定しているから、この処理いらない気もするけど + * なんか設定したものはクリアしないと気持ち悪い + */ + function clearModalTop() { + modal.style.top = ''; + } [/sourcecode] |
既存関数showModal, hideModalに修正を入れます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
[sourcecode lang="diff"] /** * モーダルを開く */ function showModal() { + // モーダルウィンドウのtop値をセット + setModalTop(); // モーダルベースレイヤを表示する baseLayer.style.visibility = 'visible'; } /** * モーダルを閉じる */ function hideModal() { // モーダルベースレイヤを非表示にする baseLayer.style.visibility = 'hidden'; + // モーダルウィンドウのtop値をクリア + clearModalTop(); } [/sourcecode] |
これで、モーダルウィンドウを開く時に、画面内に表示がされるようになったかと思います。
問題点
・・・ただ、これだけの実装だと、こんなことが起こります。
- モーダルウィンドウの長さによっては、画面からはみ出して閲覧できない状態になる。
- モーダルウィンドウが複数ある場合はどうしたらいいの?ついでに、そのモーダルウィンドウをトリガリンクから指定して呼び出したいんだけど?
1は、以下のような状態のことですね。
次回は、上記問題点を解決する実装をしていきます。
※・・・と言いつつも、実は実装は完了していて、GitHubにあがっているので、興味がある方はソース覗いてみてください。
ではでは~~