【jQuery】スクロールしてヘッダーやナビを上部に固定するには?

javascript

スマホサイトのリニューアルでスクロールしたらヘッダーが上部に固定させるようにしたいとの事で久々にjQueryを触ったのでせっかくなのでメモします。
サンプルを作りましたのでスクロールしてみてください。

サンプルを見ると背景が黄色になっている部分がスクロールすると固定されます。ここ最近のスマホのサイトではよくロゴ+ナビゲーションがあってスクロールするとナビゲーションだけヘッダー上部に固定されるサイトを見るのでそれを説明していこうかと思います。

必要なhtmlのソース

まずはhtmlのソースを準備します。

headerタグで括ってるのがヘッダーでarticleで括ってるのがメインコンテンツです。ヘッダーの最初のpタグは固定させないで、そのままスクロールさせます。
これはスマホサイトなどでロゴ+ナビの順番でナビだけ固定させたりするサイトもよく見受けられたのと、
一番上に固定させたい要素があった場合はわざわざスクロールした場合に固定させる必要がなく最初からCSSで固定させれば済むからです。


ここは固定しない

ここはスクロールで固定する

ここはメインのコンテンツの部分

ここはメインのコンテンツの部分

ここはメインのコンテンツの部分

ここはメインのコンテンツの部分

ここはメインのコンテンツの部分

ここはメインのコンテンツの部分

ここはメインのコンテンツの部分

CSSで設定する

今度はCSSの設定です。細かいCSSの設定は見た目を整えているだけなので省きます。

まずは固定させる要素のCSSですが、判り易く背景を黄色にしています。高さを設定していますがしなくてもいいです。この固定させる要素の高さが後々ポイントになってきます。(後術)

固定させるためのCSSの説明としては、「position:fixed」で「top:0」にして上部に固定させて「z-index」で他の要素より上にレイヤーに表示させるようにしています。


/* 固定させる要素 */
header p#fixes_area {
  height: 120px;
  background-color: #ffff00;
}


/* 固定させる為のCSS */

.is_fixes {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 10;
}


jQueryで実装する

いよいよ実装に入ります。ちょっと段階を区切って説明していきます。

必要な情報を変数に保存する

まずは必要な要素を取得して変数に入れておきます。まぁ特に変数に入れなくもいいんですけどね(笑)

ただ注意点として要素の高さを取得する場合はloadイベントで取得しないと高さが正常に取得できない事もあるので注意したほうがいいでしょう。これは読込の順番によるものです。詳しくは下記のサイトを参考にしてみてください。

$(window).on('load',function(){

var fixed_class = 'is_fixes', //固定させるクラス名
  $fixes_area = $('#fixes_area'), //固定させる要素
  $main = $("article"), //メインとなる要素
  fixes_pos = $fixes_area.offset().top, //固定させる要素のトップの位置
  fixes_h = $fixes_area.outerHeight(); //固定させる要素の高さ
 
 });

上記の「fixed_class」「$fixes_area」「$main」は単純に要素を入れているだけです。
そして「fixes_pos」と「fixes_h」は今回のポイントとなる変数です。

スクロールイベントでスクロール量をしらべて条件判定をする

jQueryにスクロールした場合の「scroll」イベントがあるので、スクロールしたらイベントが発火するようにします。そして下記の様な処理をします。

  • 1:window全体のスクロール量を調べて変数「value」に保存する
  • 2:スクロール量が固定させる要素のポジションを越えたかif文で条件分岐する
  • 3:スクロール量を超えた場合は、addClassで固定するクラスを設定する

//スクロールイベント
$(window).on('scroll', function() {
	
	//window全体のスクロール量を調べる
	var value = jQuery(this).scrollTop();
	
	//スクロール量が固定する要素のポジションを越えたか調べる
	if (value > fixes_pos){ 
	
	//addClassで固定するクラスを設定
	$fixes_area.addClass(fixed_class);
	
	}else{
	
	//超えていなければクラスを消す
	$fixes_area.removeClass(fixed_class);
	}

	

と上記のようにすればヘッダーは固定できます。

固定した要素の高さを下の要素に設定する

さて、固定させるのは割と簡単にできます。これでもいいのですが、実際これでスクロールするとひとつ気になる事がでてくると思います。
それは、要素を固定させると、その前後の要素との間にすっぽりと隙間ができて高さが無くなるので、下の要素(今回で言えばメインコンテンツの要素)が突然、上にガクッと動いて詰まるような動きをします。

それを防ぐために、すぐ下にある要素に隙間が出来た分の高さ=固定させた要素の高さを「margin-top」で設定してあげることでガクッと詰まるような動きをしないでスムーズになります。


//スクロールイベント
$(window).on('scroll', function() {
	
	//window全体のスクロール量を調べる
	var value = jQuery(this).scrollTop();
	
	//スクロール量が固定する要素のポジションを越えたか調べる
	if (value > fixes_pos){ 
	
	//addClassで固定するクラスを設定
	$fixes_area.addClass(fixed_class);
	
	//固定した要素の高さ分のマージンを設定
	$main.css({
      "margin-top": fixes_h
    });
	}else{
	
	//超えていなければクラスを消す
	$fixes_area.removeClass(fixed_class);
	
	//固定した要素の高さ分のマージンを消す
	$main.css({
      "margin-top": 0
    });
	
	}

	

以上で、スクロールしてヘッダーやナビを上部に固定させる説明は終わりです。割とさくっと実装できます。