サイト制作に関するメモ書き

HOME > JavaScript > jQuery > モーダルの処理を自作する

モーダルの処理を自作する

汎用的に流用できるような、簡易なモーダルを作成してみます。

サンプルコード

まずはモーダルを開くリンク部分です。
data属性で開くモーダルを設定するようにします。

<a href="" data-modal-link="modal-a">モーダルAを開く</a>
<a href="" data-modal-link="modal-b">モーダルBを開く</a>

data-modal-linkにモーダル名を指定してください。

次にモーダル部分です。
モーダルの要素にdata-modal-contentを設定して、先ほどリンクに設定したモーダル名を入れます。

<div class="modal-bg js-modalclose"></div>
<div class="modal" data-modal-content="modal-a">
  <p>モーダルAのコンテンツです。</p>
  <button class="js-modalclose">閉じる</button>
</div>
<!-- END modal-a -->
<div class="modal" data-modal-content="modal-b">
  <p>モーダルBのコンテンツです。</p>
  〜 略 〜
  <p>モーダルBのコンテンツです。</p>
  <button class="js-modalclose">閉じる</button>
</div>
<!-- END modal-b -->

.modal-bgがモーダルの背景、.modalがモーダル部分で、背景などに設定している.js-modalcloseはクリックしたらモーダルを閉じるようにJavaScriptで設定します。

次にCSSです。

.modal-bg {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 9500;
  background: rgba(0, 0, 0, 0.75);
}
.modal.is-show {
  display: block;
}
.modal {
  display: none;
  position: fixed;
  top: 50%;
  left: 50%;
  width: 600px;
  z-index: 9800;
  background: #ffffff;
  transform: translate(-50%, -50%);
}
.modal-bg.is-show {
  display: block;
}

.modal-bg、.modal共にデフォルトでは非表示にして、.is-showが付与されると表示されるように設定しています。

最後にJavaScriptです。

$(function() {
	// モーダルを開く
	$(document).on('click', '[data-modal-link]', function(e) {
		e.preventDefault();
		var target = $(this).data('modalLink');
		modal_open(target);
	});

	// モーダルを閉じる
	$('.js-modalclose').on('click', function(e) {
		e.preventDefault();
		modal_close();
	});
});

// モーダルを開く
function modal_open(target) {
	$('[data-modal-content = ' + target + ']').addClass('is-show');
	$('.modal-bg').addClass('is-show');
}

// モーダルを閉じる
function modal_close() {
	$('[data-modal-content]').removeClass('is-show');
	$('.modal-bg').removeClass('is-show');
}

クリックしたdata属性の値を使って、対になるモーダルを表示したり閉じたりしています。
モーダルのデモページ

これで基本的な動作は問題ないのですが、モーダルの配置をposition: fixed;で中央配置にしているため、モーダルBのようにモーダルないが長い場合にモーダルの上下が切れてしまいます。
この対応策として、モーダルの高さが画面高さより高い場合、position: absolute;での配置になるようにしてみます。

$(function() {
	// モーダルを開く
	$(document).on('click', '[data-modal-link]', function(e) {
		e.preventDefault();
		var target = $(this).data('modalLink');
		modal_open(target);
	});

	// モーダルを閉じる
	$('.js-modalclose').on('click', function(e) {
		e.preventDefault();
		modal_close();
	});

  $(window).on('resize', function() {
    modal_position();
  });
});

// モーダルを開く
function modal_open(target) {
	$('[data-modal-content = ' + target + ']').addClass('is-show');
	$('.modal-bg').addClass('is-show');
	modal_position();
}

// モーダルを閉じる
function modal_close() {
	$('[data-modal-content]').removeClass('is-show');
	$('.modal-bg').removeClass('is-show');
}

// モーダルの位置調整
function modal_position() {
	var $modal = $('[data-modal-content].is-show');
	if($modal.length) {
		var winH = $(window).height();
		var modalHeight = $modal.outerHeight();
		if(winH <= modalHeight) {
			var winSctop = $(window).scrollTop();
			$modal.css({
				position: 'absolute',
				top: winSctop + 10,
				transform: 'translateX(-50%)'
			});
		} else {
			$modal.removeAttr('style');
		}
	}
}

これでモーダル内が高い場合でも、スクロールですべて表示できるようになりました。
モーダルが長い場合のデモページ
 

モーダルを切り替える

モーダル内から別のモーダルに切り替えられるようにしてみます。
モーダル内に切り替え用のボタンを追加します。

<div class="modal-bg js-modalclose"></div>
<div class="modal" data-modal-content="modal-a">
  <p>モーダルAのコンテンツです。</p>
  <button data-modal-change="modal-b">モーダルBへ</button>
  <button class="js-modalclose">閉じる</button>
</div>
<!-- END modal-a -->
<div class="modal" data-modal-content="modal-b">
  <p>モーダルBのコンテンツです。</p>
  〜 略 〜
  <p>モーダルBのコンテンツです。</p>
  <button data-modal-change="modal-a">モーダルAへ</button>
  <button class="js-modalclose">閉じる</button>
</div>
<!-- END modal-b -->

ボタンにdata-modal-changeを設定して、値には開きたいモーダルを指定しています。

JavaScriptに切り替えの処理を追加します。

$(function() {
	// モーダルを開く
	$(document).on('click', '[data-modal-link]', function(e) {
		e.preventDefault();
		var target = $(this).data('modalLink');
		modal_open(target);
	});

	// モーダルを切り替える
	$(document).on('click', '[data-modal-change]', function(e) {
		e.preventDefault();
		var target = $(this).data('modalChange');
		modal_change(target);
	});

	// モーダルを閉じる
	$('.js-modalclose').on('click', function(e) {
		e.preventDefault();
		modal_close();
	});

  $(window).on('resize', function() {
    modal_position();
  });
});

// モーダルを開く
function modal_open(target) {
	$('[data-modal-content = ' + target + ']').addClass('is-show');
	$('.modal-bg').addClass('is-show');
	modal_position();
}

// モーダルを切り替える
function modal_change(target) {
	$('[data-modal-content]').removeClass('is-show');
	$('[data-modal-content = ' + target + ']').addClass('is-show');
	modal_position();
}

// モーダルを閉じる
function modal_close() {
	$('[data-modal-content]').removeClass('is-show');
	$('.modal-bg').removeClass('is-show');
}

// モーダルの位置調整
function modal_position() {
	var $modal = $('[data-modal-content].is-show');
	if($modal.length) {
		var winH = $(window).height();
		var modalHeight = $modal.outerHeight();
		if(winH <= modalHeight) {
			var winSctop = $(window).scrollTop();
			$modal.css({
				position: 'absolute',
				top: winSctop + 10,
				transform: 'translateX(-50%)'
			});
		} else {
			$modal.removeAttr('style');
		}
	}
}

別のモーダルに切り替えるデモページ
 

ページアクセス時にモーダルを表示する

特定のページからアクセスした場合にモーダルを表示するなどできるように、パラメータでモーダルを最初から開けるようにしてみます。

$(function() {
	// タブのパラメータがついている時の対応
	var modalParam = get_modal_param();
	if($('[data-modal-content="' + modalParam + '"]').length > 0) {
		modal_open(modalParam);
	}

	// モーダルを開く
	$(document).on('click', '[data-modal-link]', function(e) {
		e.preventDefault();
		var target = $(this).data('modalLink');
		modal_open(target);
	});

	// モーダルを切り替える
	$(document).on('click', '[data-modal-change]', function(e) {
		e.preventDefault();
		var target = $(this).data('modalChange');
		modal_change(target);
	});

	// モーダルを閉じる
	$('.js-modalclose').on('click', function(e) {
		e.preventDefault();
		modal_close();
	});

  $(window).on('resize', function() {
    modal_position();
  });
});

// URLのパラメータ取得
function get_modal_param() {
	var params = [];
	var param = location.search.substring(1).split('&');
	for(var i = 0; i < param.length; i++) {
		params[i] = param[i].split('=');
	}
	for(var i = 0; i < params.length; i++) {
		if(params[i][0] === 'modal' &&  params[i][1] !== undefined) {
			return params[i][1];
		}
	}
	return false;
}

// モーダルを開く
function modal_open(target) {
	$('[data-modal-content = ' + target + ']').addClass('is-show');
	$('.modal-bg').addClass('is-show');
	modal_position();
}

// モーダルを切り替える
function modal_change(target) {
	$('[data-modal-content]').removeClass('is-show');
	$('[data-modal-content = ' + target + ']').addClass('is-show');
	modal_position();
}

// モーダルを閉じる
function modal_close() {
	$('[data-modal-content]').removeClass('is-show');
	$('.modal-bg').removeClass('is-show');
}

// モーダルの位置調整
function modal_position() {
	var $modal = $('[data-modal-content].is-show');
	if($modal.length) {
		var winH = $(window).height();
		var modalHeight = $modal.outerHeight();
		if(winH <= modalHeight) {
			var winSctop = $(window).scrollTop();
			$modal.css({
				position: 'absolute',
				top: winSctop + 10,
				transform: 'translateX(-50%)'
			});
		} else {
			$modal.removeAttr('style');
		}
	}
}

33〜46行目でURLのパラメータからモーダルの設定を取得して、4〜6行目で該当のモーダルを開いています。
パラメータでモーダルを開くデモページ
 

初回ページアクセス時のみモーダルを表示する

最後に初回アクセスのみモーダルを開くようにしてみます。
仕組み的には以前投稿している以下の記事と同じ内容です。
WebStorageで1回目のアクセス時のみモーダルを表示する

$(function() {
	// 1回目のアクセスのみモーダルを表示
	var firstAccess = 'modal-a';
	if(sessionStorage.getItem(firstAccess) === null) {
		sessionStorage.setItem(firstAccess, 'on');
		modal_open(firstAccess);
	}

	// タブのパラメータがついている時の対応
	var modalParam = get_modal_param();
	if($('[data-modal-content="' + modalParam + '"]').length > 0) {
		modal_open(modalParam);
	}

	// モーダルを開く
	$(document).on('click', '[data-modal-link]', function(e) {
		e.preventDefault();
		var target = $(this).data('modalLink');
		modal_open(target);
	});

	// モーダルを切り替える
	$(document).on('click', '[data-modal-change]', function(e) {
		e.preventDefault();
		var target = $(this).data('modalChange');
		modal_change(target);
	});

	// モーダルを閉じる
	$('.js-modalclose').on('click', function(e) {
		e.preventDefault();
		modal_close();
	});

  $(window).on('resize', function() {
    modal_position();
  });
});

// URLのパラメータ取得
function get_modal_param() {
	var params = [];
	var param = location.search.substring(1).split('&');
	for(var i = 0; i < param.length; i++) {
		params[i] = param[i].split('=');
	}
	for(var i = 0; i < params.length; i++) {
		if(params[i][0] === 'modal' &&  params[i][1] !== undefined) {
			return params[i][1];
		}
	}
	return false;
}

// モーダルを開く
function modal_open(target) {
	$('[data-modal-content = ' + target + ']').addClass('is-show');
	$('.modal-bg').addClass('is-show');
	modal_position();
}

// モーダルを切り替える
function modal_change(target) {
	$('[data-modal-content]').removeClass('is-show');
	$('[data-modal-content = ' + target + ']').addClass('is-show');
	modal_position();
}

// モーダルを閉じる
function modal_close() {
	$('[data-modal-content]').removeClass('is-show');
	$('.modal-bg').removeClass('is-show');
}

// モーダルの位置調整
function modal_position() {
	var $modal = $('[data-modal-content].is-show');
	if($modal.length) {
		var winH = $(window).height();
		var modalHeight = $modal.outerHeight();
		if(winH <= modalHeight) {
			var winSctop = $(window).scrollTop();
			$modal.css({
				position: 'absolute',
				top: winSctop + 10,
				transform: 'translateX(-50%)'
			});
		} else {
			$modal.removeAttr('style');
		}
	}
}

3行目で開くモーダルを指定しています。
これで初回アクセスのみモーダルを開けくようになりました。
初回表示のみモーダルを表示するデモページ
 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

▲PAGE TOP