最近良く見かけるモーダルウィンドウですが、
モーダルのサイズが大きいと画面外にはみ出してしまい、全てを表示することが出来ません。
スクロールしたとしても、モーダルの背景であるメインコンテンツがスクロールされてしまいます。
そこで、モーダルが表示されている間のスクロール対象を、背景のメインコンテンツではなく、
モーダル自身に与えてあげることで、画面外に広がったモーダルコンテンツを全て表示することが可能です。
今回は、そんなスクロール可能なモーダルを手軽に構築する方法を解説します。
また、そんなモーダルをスクロール可能にする一連の処理を
jQueryのプラグインとして作成しましたので、宜しければお使い下さい。
一般的なモーダルの実装
一般的に良く見られるモーダルの実装は、CSSのpositionでfixedを指定し、
絶対位置にて表示することで、メインコンテンツの上にモーダルとしてコンテンツを表示させています。
表示方法は、JavaScriptで毎度作成する方法もありますし、
予めHTMLを構築しておいて、CSSのdisplayをnoneにしておき、
デフォルトでは非表示、表示する際はCSSのdisplayをblockに変更することで表示さる方法を取ることもあります。
私個人的には後者のCSSでdisplayの値によって表示・非表示を切り替える方法を取る事が多いです。
ですので今回の解説でも、「CSSでdisplayの値によって表示・非表示を切り替える方法」を基準に解説していきます。
一般的なモーダルの問題点
前述にて、一般的なモーダルの実装方法ではCSSのpositionをfixedにて行うと解説しました。
この方法では、とても手軽にモーダルを実装することが出来ますが、
一つ問題点があります。
それは、ブラウザ領域よりも大きいコンテンツをモーダルとして扱う事が出来ない事です。
通常、ブラウザの画面サイズを超えたコンテンツはスクロールすることで閲覧可能ですが、
positionのfixedは絶対位置の配置ですので、スクロールすることが出来ません。
スクロールしようとすると、スクロールされるのはモーダルが表示されている背景の
メインコンテンツがスクロールされてしまいます。
この現象を問題視し、小さなモーダルに対して内部スクロール(overfrow:scroll)を実装しているサイトを
頻繁に見かけますが、ちょっとUI的に扱いにくいと思います。
また、背景がスクロールされてしまう現状も、出来れば防ぎたいはずです。
大きいモーダルを扱うサイト
大きいモーダルを実装しているサイトでは、
内部スクロール(overfrow:scroll)にて対応している事が多いと解説しました。
しかし、中にはスクロール対象をモーダルに変更させて、
上手くモーダル上のコンテンツをスクロール可能にしているサイトがあります。
例を挙げますと、twitterのユーザー名をクリックした際に表示されるプロフィールも
モーダル表示ですがモーダル領域自体がスクロールされます。
他にも、GMailにて添付されたテキストファイルをGMail上で開く際も、
同様にモーダルとして表示された内容がスクロール対象です。
どちらも実装方法は異なりますし、
内部スクロール(overfrow:scroll)を上手く使用しているサイトもあります。
ですが、目的とする内容は同じで、
「モーダルにて内容の多いコンテンツを表示させる際には
モーダル自体をスクロール対象にしたい」
かと思います。
今回は、私なりに上記の目的を実現させる為に考えた方法について解説します。
より簡単に実装出来るようにjQueryのプラグインとして作成していますので、
気に入って頂ければ自由にお使いいただいて構いません。
スクロール可能なモーダルの考え方
まず、通常良く見られるモーダルの実装方法では、
「メインコンテンツの上にモーダルコンテンツを配置する」という考え方です。
これは、あくまでもブラウザのメインとなる制御対象はメインコンテンツですので、
スクロール対象もメインコンテンツとなります。
ここで逆の発想をしてみます。
「メインコンテンツの上にモーダルコンテンツを配置する」ではなく、
「モーダルコンテンツの背景としてメインコンテンツを配置する」という考え方です。
すると、メインとなる制御はモーダルコンテンツとなりますので、
スクロール対象はモーダルコンテンツとなり、
メインコンテンツはスクロールされずに留まります。
しかし、そのまま実装するには問題点として下記が挙げられます。
- DOM構造を予めモーダルを意識した構造にする必要がある。
- モーダル表示前のメインコンテンツのスクロール位置の保存と復帰
共に、jQueryのプラグインとして予め調整する処理を用意しておけば、
問題点は解決されるはずです。
後はどれだけ手軽に実装することが出来るかですが、
次に今回は解説するjQueryプラグインの使い方について解説します。
jQueryモーダルプラグインの使い方
使い方はとても簡単です。
まず、下準備としてモーダルコンテンツを予めHTML上に作成しておき、
CSSのdisplayをnoneにして非表示にしておきます。
そしてメインコンテンツ全体を囲った要素を一つ用意しておきます。
後は読み込んだjQueryプラグインを読み込んで、
メインコンテンツとモーダルコンテンツを指定して
表示・非表示処理を実行します。
具体的には下記のような使い方です。
// #mainに対して、モーダルとして#modal-layerを表示 $('#main').modalShow('#modal-layer'); // 表示すると共に、追加でCSSを指定する $('#main').modalShow('#modal-layer',{'top':'100px'}); // メソッドチェインにてCSSを追加することも可能 $('#main').modalShow('#modal-layer').css('top':'100px'); // モーダルを非表示にする $('#main').modalHidden('#modal-layer');
また、モーダルの背景となる半透明のグレイアウトは自動的に構築されます。
jQueryモーダルプラグインのソース
早速ですが、手軽にスクロール可能なモーダルを実装するjQueryプラグインのソースを公開します。
解説の為にコメントを多めに書いていますので、お使いの際にはコメントを除去して頂ければ幸いです。
また、デフォルトの設定や、より扱い易くする為に改変を加えても結構です。
;(function($) { // モーダルを表示する $.fn.modalShow = function( modal_selector, option_css ){ // デフォルト値を構築 var defaults = { 'display' : 'block', 'position' : 'absolute', 'z-index' : '9999', }; // 引数とデフォルト値をマージしてモーダルのCSSとする var css = $.extend( defaults, option_css ); // メインコンテンツのJQueryオブジェクト $mainContent = this; // モーダルのJQueryオブジェクト $modal = $(modal_selector); // グレイレイヤーのJQueryオブジェクト $glayLayer = $('').css({ 'position' : 'fixed', 'background-color' : 'rgb(0, 0, 0)', 'top' : '0px', 'left' : '0px', 'z-index' : '-1', 'width' : '100%', 'height' : '100%', 'min-height' : '100%', 'opacity' : '0.5', }); // メインコンテンツの位置を固定する $mainContent.css({ 'position' : 'fixed', 'width' : '100%', 'top' : '-' + $(window).scrollTop() + 'px', 'left' : '-' + $(window).scrollLeft() + 'px', }); // モーダルのDOM位置を移動する $mainContent.after( $modal ); // モーダルのCSSをセット $modal.css( css ); // グレイレイヤーを追加 $modal.prepend( $glayLayer ); // スクロール位置を初期化する $(window).scrollTop(0); $(window).scrollLeft(0); // メソッドチェインの為にモーダルを対象としてjQueryオブジェクトを返却 return( $modal ); } // モーダルを非表示にする $.fn.modalHidden = function( modal_selector ){ // メインコンテンツのJQueryオブジェクト $mainContent = this; // モーダルのJQueryオブジェクト $modal = $(modal_selector); // メインコンテンツの位置を固定する $mainContent.css({ 'position' : 'static', }); // モーダルを非表示にする $modal.css({ 'display' : 'none', }); // グレイレイヤーを削除しておく $modal.find('#modal-gray-layer').remove(); // モーダルのCSSをセット $modal.css({ 'display' : 'none', }); // スクロール位置を復帰する $(window).scrollTop( Math.abs( parseInt( $mainContent.css( 'top') ) ) ); $(window).scrollLeft(Math.abs( parseInt( $mainContent.css( 'left')) ) ); // メソッドチェインの為にモーダルを対象としてjQueryオブジェクトを返却 return( $modal ); } })(jQuery);
「もっとこうしたら汎用的だし手軽で良くなるよ!」
「バグがあるよ!」
など、今回公開したjQueryプラグインに対して様々なコメントを頂ければ幸いです。
せっかく作成したので、どんどん使い易いようにしていきたいと思います。
ご協力、宜しくお願い致します。
おこがましいですが、デモがあると嬉しいです。
返信削除メインコンテンツもスクロールする高さで、モーダルもスクロールする高さであると、非常に助かります。