jQuery | スクロール量によって固定要素を表示

[outline]

ページ内にボタンやバナーを画面固定したい時、position: fixed などで固定できますが、「最初に目に入るメインビジュアルには被らせたくない」「footerには被らせたくない」というように、決まった範囲内でのみ表示しておきたいときに使えます。

動作イメージ

スクロールがsectionCに入ると(sectionCが画面内に入ると)画面下部に固定要素が表示され、sectionDが画面内に入ると非表示となります。

See the Pen スクロール量によって固定要素を表示 by uta (@utamaro) on CodePen.

下の画像はページ全体をざっくり分けたイメージ図になります。

各セクションをA~Dに割り振り、Cを表示開始トリガー、Dを表示終了のトリガーとしています。(要素の上部がトリガーの位置となります)

スクロールをしていき、Cが画面内に入ると固定要素が表示され、Dが画面内に入ると固定要素が非表示となります。

おおまかな作り方

表示し始めたい箇所の要素と表示を終わらせたい箇所の要素にID名を指定し、トリガーとします。固定要素にもID名をつけておきます。

javascriptでページトップからのそれぞれのトリガー位置とスクロールの量を取得。スクロール量が1つ目のトリガーよりオーバーしたら表示、2つ目のトリガーを過ぎたら非表示するようにします。

なお、fadeInやfadeOut動作はjQueryのほうが滑らかなので、部分的にjQueryを使用しました。

サンプルコード

HTML

表示開始のトリガーとなる要素にidjs-appearTrigger、表示終了のトリガーとなる要素にidjs-hiddenTrigger、固定要素にidjs-fixedBlockを指定します。

固定要素はここでは一番最後に記述しています。

<div class="blockA">....</div>
<div class="blockB">....</div>
<div class="blockC" id="js-appearTrigger">....</div>
<div class="blockD" id="js-hiddenTrigger">....</div>
<div class="btn" id="js-fixedBlock">....</div>

CSS

cssでは固定要素を予め非表示にしておき、前面に来るよう念のためz-indexを指定しています。
※HTMLで固定要素を先に書くと、後に書いた要素が前面に被ってしまうので、z-indexは必須です。z-indexが効いていない場合は、全面にきている要素にposition: relative;を指定してあげるとうまくいったりします。

.btn {
  display: none;
  width: 300px;
  position: fixed;
  bottom: 0;
  left: 50%; /* 中央に表示 */
  transform: translateX(-50%); /* ずらし過ぎた分元に戻す */
  z-index: 10; /*前面に表示されていれば1でも2でもOK*/
}

上記のcssは要素の幅を300pxに指定し中央寄せにしていますが、幅100%の場合はleft: 0;でぴったり左端にくっつけてあげて、transform~の記述も必要なし。

javascript

</body>直前辺りに<script>タグで囲って下記のコードを記述。

  const fixedBlock = document.getElementById('js-fixedBlock');
  const appearTrigger = document.getElementById('js-appearTrigger');
  const hiddenTrigger = document.getElementById('js-hiddenTrigger');

  // スクロール量で下部のボタンを表示・非表示
  window.addEventListener('scroll', function () {

    //スクロール量を取得
    var scroll = window.scrollY;
    var windowHeight = window.innerHeight; //画面の高さを取得

    //ターゲット要素の位置を取得
    var appearTriggerPos = appearTrigger.getBoundingClientRect().top + scroll;

    //ターゲット要素の位置を取得
    var hiddenTriggerPos = hiddenTrigger.getBoundingClientRect().top + scroll;

    if (scroll >= appearTriggerPos - windowHeight && scroll <= hiddenTriggerPos - windowHeight) {
      $('#js-fixedBlock').fadeIn();
    } else if (scroll < appearTriggerPos - windowHeight) {
      $('#js-fixedBlock').fadeOut();
    } else if (scroll > hiddenTriggerPos - windowHeight) {
      $('#js-fixedBlock').fadeOut();
    }
  });

※jQueryを使用しているので、上記のスクリプトコードより上にjQueryを読み込んでおいてください。
(CDNで読み込む場合は以下のコードを貼り付ければOK。GoogleHostedLibrariesより)

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

いくつか分岐点を作って表示と非表示を分けているだけなので、分岐点を増やせばもっと細かく表示非表示を切り替えられます。

上記では、表示トリガー <= スクロール <= 非表示トリガー のときに表示、表示トリガー > スクロール もしくは 非表示トリガー < スクロール のときに非表示としています。

備考

元々全てjavascriptで作ろうとしたが、fadeInやfadeOut部分の動作が不安定だったため、結局一部jQeryを使用。javascriptでなめらかにfadeIn・fadeOutが出来たら、ここに追記しようと思う。

モーダルウィンドウ(アクセス時に開くやつ)

ページ遷移無しでコンテンツを表示したりしなかったり。
何かと使う機会の多いモーダルウィンドウですが、ボタンや画像をクリックして閉じたり開いたりするタイプではなく、ページを開くと同時に(アクセス時に)開いた状態にしておくタイプの作りかたです。

なお、こちらのサイトのものを参考に少し改造しています。
FEVDES BLOG | 【簡単!】ページのアクセス時にモーダル(フロート)を表示するjQuery.layerBoard.js


モーダルサンプル(画面からコンテンツがはみ出すver)


モーダルサンプル(画面内におさまるver)

作ります

用意するもの

  • jQuery
  • jquery.cookie.js
  • jquery-modalLayerBoard.js
  • layerBoard.css
  • 閉じる用のボタン画像

以下のリンクからsampleファイル一式をダウンロードできます。(※jQueryとjquery-cookieはCDNを使用しています)

modal_window-sample.zip

jQuery

まず</body>直前あたりでjQueryを読み込みます。※CDNで読み込んでいます。


					
				

jquery.cookie.js

次にこちらを読み込みます。
クッキーを使ってアクセス回数を判別し、「最初のアクセス時だけモーダルウィンドウを表示させる」といったような制御ができるようにします。

ファイルはGitHubからダウンロードできます。「src」内の「jquery.cookie.js」だけで大丈夫です。
今回はこちらのCDNを使ってなるべくダウンロードするものを少なくしたいと思います。


					
				

jquery-modalLayerBoard.js

これでモーダルウィンドウを表示させたり動きを制御します。
参考サイトのファイルを使いやすいように少しいじったものです。以下のリンクから直接ダウンロードできます。

jquery-modalLayerBoard.js

					
				

ファイルの内容は以下。外部にファイルを設置できない場合などは<script>タグで囲って直接HTML上に記述します。


					/*
 * ===================================
 *	jquery.layerBoard.js
 *	@auther:kiyoty
 *	@URI:http://www.idea-clippin.com
 *	@create:2012/12/30
 * 	@License:MIT License(X11 License、X License)
 *	@modification:uta
 * ===================================
*/
(function($) {
	$.fn.layerBoard = function(option) {
		var elements = this;
		elements.each(function(){
			option = $.extend({
				delayTime: 200,
				fadeTime : 500,
				alpha : 0.5,
				limitMin : 10,
				easing: 'linear',
				limitCookie : 3	,
				countCookie : 10000
			}, option);
			var limitSec = option.limitMin * 60; //秒数に変換
			// cookieがない場合 --------------------
			if ($.cookie('layerBoardTime') == null || $.cookie('visitCount') == null) {
				LayerBoardFunc ();
				var start = new Date();	// cookieに現在の時間をセット
				$.cookie('layerBoardTime', start.getTime(), { expires: option.limitCookie,path: '/' });
				var visitCount = 1;  //訪問回数を1回に設定
				$.cookie('visitCount', visitCount, { expires: option.limitCookie });
			} else if ($.cookie('visitCount') <= option.countCookie - 1){
			// cookieがある場合 --------------------
				//Cookie"visitCount"の値に1つ足す
				visitCount = $.cookie('visitCount');
				visitCount ++;
				$.cookie('visitCount', visitCount, { expires: option.limitCookie });
				//現在のミリ秒を取得し、秒数に変換
				var now = new Date();
				secDiff = now.getTime() - $.cookie('layerBoardTime');
				secTime = Math.floor( secDiff / 1000);
				//指定時間を経過していた場合は、LayerBoardを表示
				//cookieを削除後、再度cookieに現在のミリ秒をセット
				if (secTime >= limitSec) {
					LayerBoardFunc ();
					$.cookie('layerBoardTime', null, { expires:-1,path: '/' });
					var start = new Date();
					$.cookie('layerBoardTime', start.getTime(), { expires:option.limitCookie,path: '/' });
				}
			}
			// 表示処理 --------------------	
			function LayerBoardFunc () {
			}	
			function LayerBoardFunc () {
				$('#layer_board_area').css('display', 'block');	
				$('.layer_board_bg', elements).show().animate({opacity: 0},0).delay(option.delayTime).animate({opacity: option.alpha},option.fadeTime,function(){
					$('.layer_board', elements).fadeIn(option.fadeTime);			
					//表示した際背景のスクロール禁止
					$('html, body').css('overflow', 'hidden');		
				})				
			}
			// 非表示処理 --------------------
			$('.layer_board_bg', elements).click(function() {			
				$('.layer_board , #layer_board_area', elements).fadeOut(option.fadeTime);
				$(this).fadeOut(option.fadeTime);
				$('#layer_board_area').css('display', 'none');
				//非表示にした際背景のスクロール許可
				$('html, body').css('overflow', 'auto');
			});
			// .mdl_btn_closeをクリックした時の動作(非表示処理) --------------------
			$('.mdl_btn_close', elements).click(function() {				
				$('.layer_board , #layer_board_area', elements).fadeOut(option.fadeTime);
				$('.layer_board_bg', elements).fadeOut(option.fadeTime);
				$('#layer_board_area').css('display', 'none');
				//非表示にした際背景のスクロール許可
				$('html, body').css('overflow', 'auto');
			});
			// モーダル表示用ボタンの表示処理 --------------------
			$('.layer_board_btn').click(function() {
				$('#layer_board_area').css('display', 'block');			
				$('.layer_board_bg', elements).show().animate({opacity: 0},0).delay(option.delayTime).animate({opacity: option.alpha},option.fadeTime,function(){
					$('.layer_board', elements).fadeIn(option.fadeTime);
					//表示した際背景のスクロール禁止
					$('html, body').css('overflow', 'hidden');	
				});
			});
			// 見た目処理(コンテンツが短い場合中央表示) --------------------
			var bg_height = $('.layer_board_bg').outerHeight();
			var layer_bord_height = $('.layer_board').outerHeight();
			if(bg_height + 40 >= layer_bord_height){
				$('.layer_board').addClass('shortLayer');
			}
		});
		return this;	
	};
})( jQuery );

				

layerBoard.css

モーダルウィンドウのスタイルなど。
以下からダウンロードして<head>~</head>内に外部ファイルとして読み込んでも良いし、HTML内に直接書いても大丈夫です。

layerBoard.css

					 	<link rel="stylesheet" href="...yourDirectoryPath.../layerBoard.css">
				

ファイルの内容は以下。


					/* ---------------------------------- **
		Modal Window
** ---------------------------------- */
#layer_board_area {
	display: none;
	position: fixed;
	top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    padding: 0 3vw;
    overflow-y: auto;
    box-sizing: border-box;
    -ms-overflow-style: none;
    scrollbar-width: none; /*スクロールバーを非表示*/
    z-index: 2;
}
#layer_board_area::-webkit-scrollbar {
	display:none; /*スクロールバーを非表示*/
}
.layer_board_bg {
	display: none;
	position: fixed;
	width: 100%;
	height: 100%;
	top: 0;
	bottom: 0;
	right: 0;
	left: 0;
	cursor: pointer;
	background: #000;
	z-index: 0;
}
/* --modalWindow ポップアップ部分-- */
.layer_board {
	display: none;
	position: relative;
	width: 80%;
	max-width: 800px;
	margin: 3em auto;
	padding: 4em;
	border-radius: 5px;
	box-sizing: border-box;
	background: #fff;
	z-index: 10;
}
.layer_board.shortLayer {
	margin: 0;
	top: 50%;
	left: 50%;
	transform: translate(-50%,-50%);
}
/* --close ボタン-- */
.layer_board .mdl_btn_close.circle_btn {
	position: absolute;
	top: 10px;
	right: 15px;
	width: 30px;
	height: 30px;
	background-color: #000;
	background-image: url("btn_close.png");
	background-repeat: no-repeat;
	background-size: 18px;
	background-position: 50%;
	border-radius: 50%;
	border: 1px solid #ccc;
	transition: .15s;
}
.layer_board .mdl_btn_close.circle_btn:hover {
	background-color: #FDB53F;
	border: 1px solid #FDB53F;
}
@media screen and (max-width:480px) {
	.layer_board {
		width: 90%;
		margin: 3em auto;
		padding: 1.5em;
	}
	.layer_board .mdl_btn_close.circle_btn {
		width: 26px;
		height: 26px;
		background-size: 14px;
	}
}
/* --コンテンツ部分の装飾-- */
.layer_borad_title {
	font-size: 200%;
	font-weight: 200;
	color: #ED344E;
}
.layer_borad_content {
	margin: 1em auto 1.5em;
}
.layer_board .square_btn {
	display: block;
    position: relative;
    width:160px;
    margin: 0 auto;
    padding: 10px;
    border:2px solid #111;
    border-radius: 2px;
    font-size: 1.2em;
    font-weight: 300;
    color: #111;
    text-align: center;
    letter-spacing: 1px;
    text-decoration: none;
    transition: .15s;
}
.layer_board .square_btn:hover {
	background: #111;
	color: #fff;
}
				

スクリプトを実行させるコードを書く

「jquery-modalLayerBoard.js」を実行させるために、以下のコード(どちらか)をhtmlに記述します。
<script>タグで囲って、読み込んだ「jquery-modalLayerBoard.js」よりも下に記述してください。


					//デフォルト設定のまま動かす場合はこれ
$(function(){
	$('#layer_board_area').layerBoard();
})
//動きやアクセス回数を制御する場合は以下のように記述して数値を変える
$(function(){
	$('#layer_board_area').layerBoard({
		delayTime: 200,		//表示までの待ち時間
		fadeTime : 500,		//表示開始から表示しきるまでの時間
		alpha : 0.8,		//背景レイヤーの透明度
		limitMin : 0,		//何分経過後に再度表示するか/分(0で再表示なし)
		easing: 'linear',		//イージング
		limitCookie : 0	,	//cookie保存期間/日(0で開くたび毎回表示される)
		countCookie : 1000	//何回目のアクセスまで適用するか(cookie保存期間でリセット)
	});
})
				

たとえば、毎日最初のアクセス時だけモーダルウィンドウを開く場合は
limitCookie: 1, countCookie: 1
と設定します。

モーダルウィンドウを設置する

<body>タグ直後にモーダルウィンドウとなる部分のコードを書きます。

モーダルウィンドウ全体を囲う「#layer_board_area」、モーダル背景部分となる「.layer_board_bg」、モーダルコンテンツ部分となる「.layer_board」は除かないでください。


					
	<section>
			<!-- 
				ここに内容
			 -->
		<a href="#">閉じる</a>
	</section><!-- layer_board -->
<!-- layer_board_area -->
				

上記のコードではコンテンツ内容を囲う.layer_borad_contentを追加し、さらにモーダル上の四角い閉じるボタン(.square_btn)と右上の閉じるボタン(.circle_btn)を追加しています。背景をクリックしても閉じるので、不要であれば外して大丈夫。

モーダルウィンドウを手動で再表示させるボタンを設置するには、「.layer_board_btn」クラスをつけたボタンを設置してください。


					<button>モーダルウィンドウボタン</button>