【jQuery】かんたん!ヘッダーナビを自動で非表示にするsetTimeout()とclearTimeout()

2014.8.30 jQuery

かんたん!スクロールするとスライドインするナビを自動で非表示にするjQueryのsetTimeout()とclearTimeout()|ツーブロッカ satohmsys

スクロールすると画面上部にヒョコっと現れるメニューをjQueryで実装してみます!

CSSを調節すればスマートフォン用のwebサイトにも使えるので、キャンペーンページとかクーポンとかセールとか、強引な導線設計にもってこいなデザインです。

さらに、今回はユーザーに気を配って時間経過による非表示機能を実装しようと思います!

かんたん!スクロールするとスライドインするナビを自動で非表示にするjQueryのsetTimeout()とclearTimeout()

まずはHTMLを準備します。

HTML

<header class="slidedown">
	<p>Slide down now.</p>
	<button>button-A</button>
	<button>button-B</button>
	<button>button-C</button>
	<p class="values">Scroll value:<strong class="sv"></strong>/ Limit <strong class="lmt"></strong></p>	
</header>
<main>
	<section id="to_section1">1</section>
	<section id="to_section2">2</section>
	<section id="to_section3">3</section>
	<section id="to_section4">4</section>
	<section id="to_section5">5</section>
	<section id="to_section6">6</section>
</main>

	<script src="http://code.jquery.com/jquery-1.8.3.min.js"></script>

</body>

CSS

		body , html , p {
			margin: 0;
			padding: 0;
			font-family: century gothic;
		}

		section{
			height: 500px;
			padding: 250px 0;
			text-align: center;
			font-size: 200px;
			color: #fff;
			}
		section:nth-child(odd){
			background-color: #cfc;
		}
		section:nth-child(even){
			background-color: #ccf;
		}

		/*スライドダウンメニュー*/
		.slidedown{
			/*幅は任意で。*/
			width: 80%;
			margin: 0px ;
			padding : 20px 10%;
			text-align: center;
			background-color: #ffd;

			/*上部固定*/
			position: fixed;
			top: 0;
		}

		.slidedown button{
			width : 33%;
			padding: 20px 0;
			display: inline-block;
			background-color: #dadada;
			-webkit-box-shadow: 0 4px 0 #333;
			box-shadow: 0 4px 0 #333;
			border : none;
			position: relative;
		}

		.slidedown button:last-child{margin-right: 0;}

		.slidedown button:hover , .slidedown button:active , .slidedown button:focus{
			bottom: -4px;
			-webkit-box-shadow: none;
			box-shadow: none;
			background-color: #fde;
		}

メニューをjQueryで非表示にする前のHTMLだけのデモ

上部のメニュー.slidedownが、最初は隠れているけれどスクロールした量に応じて上から降りてくるイメージです。
画面にフィックスさせるために

  • position:fixed;
  • top:0;

この2点は必須で、幅は任意で調節してください。
ただ、このタイプのUIなら横幅いっぱいに領域が広がっていたほうが美しい気がします。。

わかりやすくするためにメニューを隠していませんが、実装を始めるにあたりdisplay:noneを書き足しましょう。

CSS

		/*スライドダウンメニュー*/
		.slidedown{
			/*幅は任意で。*/
			width: 80%;
			margin: 0px ;
			padding : 20px 10%;
			text-align: center;
			background-color: #ffd;

			/*上部固定*/
			position: fixed;
			top: 0;

			/*スライドインさせるため、最初は非表示*/
			display: none;
		}

では、jQueryを書いていきます。

.on()で、スクロールしたときにメニューをスライドダウンさせるjQuery

もちろん、jQueryライブラリを読ませておいてください。

jQueryライブラリ

<script src="http://code.jquery.com/jquery-1.8.3.min.js"></script>

jQuery

	$(function(){

		var contHeight = $('body').height(); //コンテンツ高さ

		var $Limit = contHeight / 5 ; //コンテンツ高さの5分の1 

		$('.lmt').text($Limit); //テスト用

		var slideMenu = $('.slidedown');

		$(window).on('scroll' , function(){
			
			var $scrollValue = $(window).scrollTop();//スクロール値
			$('.sv').text($scrollValue); //テスト用

			if($scrollValue >= $Limit ){
				slideMenu.slideDown('slow');
			}

		});

	});

//テスト用と書いてある行は、今回、特に動作に影響しません。

そこそこスクロールするとメニューが出てくるだけのデモ

4行目、6行目ぐらいの変数に注目してください。これらがメニューが出現するタイミングを設定する役目を果たしています。

変数contHeightbodyの高さを取得しています。
JavaScriptで画面サイズを取得する | かえラボBlog

そのbodyの高さを5で割った値$Limitです。コンテンツの1/5までスクロールしたらメニューが出るようにしています。

かんたん!スクロールするとスライドインするナビを自動で非表示にするjQueryのsetTimeout()とclearTimeout()

ここは5でなくても、3で割ってもいいです。割る値が大きければ大きいほど、数値が小さくなるので、のちにメニューが降りてくるポイントが早くなるということです。

次にこの辺りですが、ここでスクロール時に起こるイベントを設定しています。

$(window).on('scroll' , function(){
			
			var $scrollValue = $(window).scrollTop();//スクロール値
			$('.sv').text($scrollValue); //テスト用

			if($scrollValue >= $Limit ){
				slideMenu.slideDown('slow');
			}

		});

$scrollValueはウィンドウ上部からのスクロール値を代入しています。
スクロールイベントの中に入れないと意味が無いので注意しましょう!
scrollTop() – jQuery 日本語リファレンス
1分でわかるjQueryのscrollTop() スクロール位置取得の使い方 | iwb.jp

そのスクロール値が、先ほどの$Limit(コンテンツ高さの1/5)よりも大きくなった時に、「slideMenu.slideDown(‘slow’)」処理が行われます。

ここでメニューを表示させています。ニュルッと。
速い方がいいという方は、(‘slow’)を(‘fast’)に変えてください。
slideDown([speed], [callback]) – jQuery 日本語リファレンス

slideUpとslideDownをifで振り分けてメニューの表示/非表示

先ほどのjQueryの記述だと、全体の1/5スクロールし終えた際にメニューが出っぱなしです。

これはだらしない!という方は、if(){~}に続けて、else{~}を記述します。

jQuery

			if($scrollValue > $Limit ){//出てくる
				slideMenu.slideDown('slow');
			}else{//戻る
				slideMenu.slideUp('slow');
			}

これはif()の条件に当てはまらなかったときの処理ですので、今回の場合は、”全体の1/5よりもスクロール値が少ない場合”ということになります。

かんたん!スクロールするとスライドインするナビを自動で非表示にするjQueryのsetTimeout()とclearTimeout()

スクロール値は画面上部から、スクロールが始まる度に加減して数えているので、”全体の1/5よりもスクロール値が少ない場合”はslideUp()処理が行われます。
slideUp([speed], [callback]) – jQuery 日本語リファレンス

これにより、メニューが上へ引っ込みます。同時に、display:noneとなります。

そこそこスクロールするとメニューが出てきて、上にスクロールして戻るとメニューが引っ込んで非表示になるデモ

setTimeout()とclearTimeout()で、時間差で表示になるメニューにする

現在、ページの下にいるときにずっと上部にメニューが出ている状態です。
ページ全体の長さに対し1/5以内に収まってる時にのみ、メニューが隠れます。

せっかく下まで読んでくれているのにメニューがずっと降りているなんてだらしない!という方に、
次は、一定時間の経過でメニューが閉じるようにします。

スクリプトを書き換えます。(一部は変更なしです)

jQuery

		var contHeight = $('body').innerHeight(); //ウィンドウ高さ

		var $Limit = contHeight / 5 ; //コンテンツ高さの5分の1 

		var slideMenu = $('.slidedown');

		$('.lmt').text($Limit); //テスト用

		var slideUpTimer = false;

		$(window).on('scroll' , function(){//スクロールで随時イベント発生
			
			var $scrollValue = $(window).scrollTop();//スクロール値
			$('.sv').text($scrollValue); //テスト用

			if(slideUpTimer !== false){ //【1】slideUpTimerがfalseじゃないなら随時クリア
				clearTimeout(slideUpTimer);
			}

			if($scrollValue > $Limit ){//【2】出てくる
					slideMenu.slideDown('slow');
			}else{//スクロール値が規定に見たない場合に処理したいならこちら
					//slideMenu.slideUp('slow');
			}
			
			slideUpTimer = setTimeout(function(){//【3】戻る(3秒後に)
						slideMenu.slideUp('slow');
			} , 3000);

		});

	});

win.on(‘scroll’ , function(){~})前後が変わっています。

まず、ポイントとしては、スクロールイベントの前に変数slideUpTimer = false;を定義しています。
スクロールイベント中は、変動しない変数は定義したくないですしね。

少し進んで、以下の箇所が更にポイントです。

if(slideUpTimer !== false){ //【1】slideUpTimerがfalseじゃないなら随時クリア
				clearTimeout(slideUpTimer);
			}

			if($scrollValue > $Limit ){//【2】出てくる
					slideMenu.slideDown('slow');
			}else{//スクロール値が規定に見たない場合に処理したいならこちら
					//slideMenu.slideUp('slow');
			}
			
			slideUpTimer = setTimeout(function(){//【3】戻る(3秒後に)
						slideMenu.slideUp('slow');
			} , 3000);

変数slideUpTimerがfalseでないとき、つまり、値が入っているとき、clearTimeoutが実行されます。
JavaScriptリファレンス – clearTimeout:ITpro
これでslideUpTimerの処理をクリアしています。

そのすぐ後のifは先ほどと同じで、スクロールの量に応じメニューを出す処理です。

最後に、slideUpTimerに関数を代入しています。
setTimeoutという関数を使っています。これは、setTimeout内の処理を指定した時間だけ遅らせて実行する、という関数です。
一定時間で繰り返す(setTimeout)-JavaScript入門

slideMenuが、3秒後(3,000ミリ秒)にslideUpするという処理をslideUpTimerに入れておきます。

上記のコードに【1】~【3】まで番号が振ってありますが、この順に実行されるんですね。

  1. slideUpTimerが無効に
  2. スクロール値に応じメニュー出る
  3. 3秒後にメニュー引っ込む

で、この処理というのは.on(‘scroll’ , function(){~})内の記述であるため、ピクリとでもスクロールされた瞬間に【1】~【3】が実行されるのです。

かんたん!スクロールするとスライドインするナビを自動で非表示にするjQueryのsetTimeout()とclearTimeout()

つまり、マウスホイールを1ミリでも動かそうものなら【3】まで進んだ処理でslideUpTimerに何が入ろうと【1】のclearTimeout()にかき消されてしまうため、
【1】~【2】を行ったり来たりするわけなのです。

【3】の処理を行いたい、3秒後にメニューを閉じたい場合には、スクロールを止めるしか無いのです。

これが、3秒後にメニューが閉じる仕組みです!

そこそこスクロールするとメニューが出てきて、スクロールを止めて3秒後に自動でメニューが非表示になるデモ

ポイントとしては

  • タイマー用変数(例:slideUpTimer)は、scrollなどイベントでリアルタイムに行われる処理の外で定義すること
  • setTimeoutには、何秒後かに実行したい処理をかくこと

でし!

ちなみにこの箇所ですが

			if($scrollValue > $Limit ){//【2】出てくる
					slideMenu.slideDown('slow');
			}else{//スクロール値が規定に見たない場合に処理したいならこちら
					//slideMenu.slideUp('slow');
			}

必要に応じてelse処理でメニューを引っ込ませて非表示にしてもいいのですが、なかなか慌ただしかったのでコメントアウトしています。

 

いかがでしょう?結構簡単ですよね。

しかも便利なUIだと思います。

使いどころに寄っては極端に鬱陶しく思われそうなので注意しましょう…

 

 

でわ!

プロフィール

東京でWebデザイナー・コーダーとして、フロントエンド的なことからグラフィックデザイン的なことをして、ごにょごにょと小さく活動中。Webクリエイターでは珍しい(?) HIPHOP, R&B好き。休日はよくカフェや漫画喫茶に出向いたりパン屋に行ったり、主に散歩しています。だいたいラーメンを食べて帰ってくる、そんな過ごし方です(都内のオススメ散歩コース募集中!)。デザインのトレンドやデザイン思考、HTML、CSSからSASS、Javascript、Wordpress構築などコーディングのTIPSなどをブログにアップしていきます。その他のことはtwitter( @satohmsys )まで。