2016.10.05

【CSS , jQuery】スクロールに対応したモーダルウィンドウを実装するサンプル

Category: css / js

Tags, , , ,

スクロールに対応したモーダルウィンドウを実装するサンプルです。
レスポンシブにも対応しています。

以下のモーダルを開くボタンとモーダルウィンドウのソースを任意の場所に設置します。

html

<p><a href="" id="modal-open">モーダルを開く</a></p>

<div class="modal" id="modal">
	<div class="modal-wrap">
		<div class="modal-content">
			<div class="modal-table-wrap">
				<div class="modal-table-cell">
					<div class="modal-content-box">
						<div class="modal-content-inner">
							<p class="modal-btn-close" id="modal-btn-close">
								<span class="bar01"></span>
								<span class="bar02"></span>
							</p>
							<div class="modal-ct-text-box">
								
								<!-- ここにコンテンツ -->
								
							</div>
						</div>
					</div>
				</div>
			</div>
		</div>
	</div>
</div>

css/sass

sass / compass

.modal {
	display: none;
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 999999;
	filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#80000000,endColorstr=#80000000); 
	background: rgba(0, 0, 0, .5);
}
.modal-wrap {
	height: 100%;
	padding: 0 30px;
	overflow: auto;
	-webkit-overflow-scrolling: touch;
}
.modal-content {
	height: 100%;
	max-width: 960px;
	margin: 0 auto;
}
.modal-table-wrap {
	display: table;
	table-layout: fixed;
	height: 100%;
	width: 100%;
}
.modal-table-cell {
	display: table-cell;
	padding: 60px 0 60px;
	vertical-align: middle;
}
.modal-content-box {
	position: relative;
	margin: 0 auto;
	background: #fff;
}
.modal-content-inner {
	padding: 50px 30px 50px;
}
.modal-btn-close {
	position: absolute;
	top: -40px;
	right: 0;
	z-index: 9;
	height: 30px;
	width: 30px;
	cursor: pointer;
	span {
		display: block;
		background: #fff;
		height: 2px;
		width: 30px;
	}
	.bar01 {
		@include transform(translateY(15px) rotate(-45deg));
	}
	.bar02 {
		@include transform(translateY(13px) rotate(45deg));
	}
}
@media only screen and (max-width: 768px) {
	.modal-wrap {
		padding: 0 10px/320px*100%;
	}
	.modal-content-inner {
		padding: 40px 10px/300px*100% 40px;
	}
}

css

.modal {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 999999;
  filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#80000000,endColorstr=#80000000); 
  background: rgba(0, 0, 0, 0.5);
}

.modal-wrap {
  height: 100%;
  padding: 0 30px;
  overflow: auto;
  -webkit-overflow-scrolling: touch;
}

.modal-content {
  height: 100%;
  max-width: 960px;
  margin: 0 auto;
}

.modal-table-wrap {
  display: table;
  table-layout: fixed;
  height: 100%;
  width: 100%;
}

.modal-table-cell {
  display: table-cell;
  padding: 60px 0 60px;
  vertical-align: middle;
}

.modal-content-box {
  position: relative;
  margin: 0 auto;
  background: #fff;
}

.modal-content-inner {
  padding: 50px 30px 50px;
}

.modal-btn-close {
  position: absolute;
  top: -40px;
  right: 0;
  z-index: 9;
  height: 30px;
  width: 30px;
  cursor: pointer;
}
.modal-btn-close span {
  display: block;
  background: #fff;
  height: 2px;
  width: 30px;
}
.modal-btn-close .bar01 {
  -moz-transform: translateY(15px) rotate(-45deg);
  -ms-transform: translateY(15px) rotate(-45deg);
  -webkit-transform: translateY(15px) rotate(-45deg);
  transform: translateY(15px) rotate(-45deg);
}
.modal-btn-close .bar02 {
  -moz-transform: translateY(13px) rotate(45deg);
  -ms-transform: translateY(13px) rotate(45deg);
  -webkit-transform: translateY(13px) rotate(45deg);
  transform: translateY(13px) rotate(45deg);
}

@media only screen and (max-width: 768px) {
  .modal-wrap {
    padding: 0 3.125%;
  }

  .modal-content-inner {
    padding: 40px 3.33333% 40px;
  }
}

js

//モーダル
jQuery(document).ready(function($){
	//モーダル表示判別フラグ
	var modal_show_flg = false;
	
	var modal = $('#modal');
		
	//モーダルオープン
	$('#modal-open').click(function(e){
		e.preventDefault();
		modal.fadeIn();
		bodyFix();
		setTimeout(function() {
			modal_show_flg = true;
		}, 10);
	});
	
	//モーダルクローズ
	$('#modal-btn-close').click(function(){
		modalClose();
	});
	$(document).click(function(e) {
		var target = $(e.target);
		if(modal_show_flg === true && !target.parents('.modal-content-box').length) {
			modalClose();
			return false;
		}
		if(modal_show_flg === true && target.hasClass('modal-content-box')) {
			modalClose();
			return false;
		}
	});
	//モーダルクローズ関数
	function modalClose() {
		bodyFixReset();
		modal.fadeOut();
		modal_show_flg = false;
	}
	
	//body固定関数
	var bodyElm = $('body');
	var scrollPosi;
	function bodyFix() {
		scrollPosi = $(window).scrollTop();
		bodyElm.css({
			'position': 'fixed',
			'width': '100%',
			'z-index': '1',
			'top': -scrollPosi
		});
	}
	
	//body fixリセット
	function bodyFixReset() {
		bodyElm.removeAttr('style');
		//scroll位置を調整
		$("html, body").scrollTop(scrollPosi);
	}
});

上記のコードではモーダルを開いた時に、背景のメインコンテンツのスクロールを禁止しています。

スクロール禁止を解除する場合は、以下のようにbody固定関数を取り除きます。

//モーダル
jQuery(document).ready(function($){
	//モーダル表示判別フラグ
	var modal_show_flg = false;
	
	var modal = $('#modal');
		
	//モーダルオープン
	$('#modal-open').click(function(e){
		e.preventDefault();
		modal.fadeIn();
		setTimeout(function() {
			modal_show_flg = true;
		}, 10);
	});
	
	//モーダルクローズ
	$('#modal-btn-close').click(function(){
		modalClose();
	});
	$(document).click(function(e) {
		var target = $(e.target);
		if(modal_show_flg === true && !target.parents('.modal-content-box').length) {
			modalClose();
			return false;
		}
		if(modal_show_flg === true && target.hasClass('modal-content-box')) {
			modalClose();
			return false;
		}
	});
	//モーダルクローズ関数
	function modalClose() {
		modal.fadeOut();
		modal_show_flg = false;
	}
});

モーダルウィンドウの中央寄せを display: table; にて実装しているため、タグの階層は深めですが、IE8など古いブラウザまで幅広く表示を維持できると思います。

関連リンク

Category : css / js