見出し画像

基本のスティッキーヘッダー4種盛り


おはようございます!

先日、買い物から家に帰るとポイントカードが無いことに気づき、慌ててスーパーに戻って店員さんに聞いたり、小一時間捜索したあげく、ズボンのポケットにカードが入ってました。

どうも、若年生認知症のこうへいです。(なぜなのか)


さて、Webサイトを作っていてよくあるのが「スティッキーヘッダー」

「スティッキー(sticky)」をgoogle翻訳してみるとこんな感じ↓

スクリーンショット 2020-04-10 13.58.10


想像以上にネチョネチョな翻訳でビビりましたが、つまりこういうこと。

「スクロールしても画面上に追従してくる」(粘着質)


複雑な実装方法のものってあまりないと思っていて、基本を抑えておけばどんなサイトでも応用できるはず。


当記事で紹介するのは基本のスティッキーヘッダー4パターンを用意しました。

・基本の追従
・デザインの変更
・途中から表示
・フッター手前で非表示


パターン1:基本の追従


やってることは、jQueryでスクロールを監視して、ナビゲーションメニューの高さ分スクロールしたらクラスを付与しているだけ。


これがスティッキーヘッダーの基本の形になるので、パターン1を抑えればあとは簡単。

つまり、この部分の説明はしっかりめです。逆に、2、3、4はサクッとコード貼るだけですw


まずコードから。

今回、コピペで使うことを想定しているので、headerやnavにクラス名をつけてませんが、実際の現場ではしっかりクラス名をつけて管理してくださいね。

.site-header
.header__nav
.header__item
.site-footer
など


HTML

<header>
 <nav>
   <ul>
     <li><a href="../index.html">TOP</a></li>
     <li><a href="../demo1/index.html">そのまま追従</a></li>
     <li><a href="../demo2/index.html">デザインが変わる</a></li>
     <li><a href="../demo3/index.html">途中から表示</a></li>
     <li><a href="../demo4/index.html">フッター手前で非表示</a></li>
   </ul>
 </nav>
</header>
<main>
</main>
<footer>
</footer>


CSS

.is-fixed {
position: fixed;
top: 0;
left: 0;
z-index: 2;
width: 100%;
}

jQueryでこのクラス名をつけ外しすることで、ヘッダーを上部に固定することができます。


jQuery

$(function() {
 var $win = $(window),
     $main = $('main'),
     $nav = $('nav'),
     navHeight = $nav.outerHeight(),
     navPos = $nav.offset().top,
     fixedClass = 'is-fixed';

 $win.on('load scroll', function() {
   var value = $(this).scrollTop();
   if ( value > navPos ) {
     $nav.addClass(fixedClass);
     $main.css('margin-top', navHeight);
   } else {
     $nav.removeClass(fixedClass);
     $main.css('margin-top', '0');
   }
 });
});

スティッキーヘッダの実装は、「jQueryのスクロール監視」がポイント。


では、分解して解説してきましょう。


変数宣言

  var $win = $(window),
     $main = $('main'),
     $nav = $('nav'),
     navHeight = $nav.outerHeight(),
     navPos = $nav.offset().top,
     fixedClass = 'is-fixed';


このステートメントでは、それぞれの変数宣言とバインド(初期値の割当)してます。

変数に入れた値はいつでも変更できるので、管理がしやすくなるという利点がありますね。

単純に変数を宣言して、指定したタグやクラスを代入しています。


var $win = $(window),

「ページ全体が読み込まれた後に実行してね」という処理のために宣言しています。


navHeight = $nav.outerHeight(),

「要素の高さを求めるメソッド」で、この値はパディングやボーダーの値も含めます。


navPos = $nav.offset().top,

offsetメソッドは、「jQueryの要素の距離の値を取得するメソッド」です。

2つのプロパティがあり、topは上端からの距離、leftは左端からの距離です。

つまりここでは、<nav>の上端からの距離を初期値として変数に格納していますね。


これらを予め変数としてバインドしておくことで、jQueryの記述が楽になります。


ステートメントは「式」
バインドは「代入」
という意味です!かっこいいので言いたいだけ




スクロールイベントを監視して処理する

  $win.on('load scroll', function() {
   var value = $(this).scrollTop();
   if ( value > navPos ) {
     $nav.addClass(fixedClass);
     $main.css('margin-top', navHeight);
   } else {
     $nav.removeClass(fixedClass);
     $main.css('margin-top', '0');
   }
 });


$win.on('load scroll', function() {

「ウィンドウが読み込まれた時、スクロールイベントが発生した時に実行してね!」という意味。

その中に、スクロール監視してどんな処理をするのかを書いていきます。


var value = $(this).scrollTop();

scrollTop();は、「縦方向にどれだけスクロールされたかを調べるメソッド」です。

つまり、ウィンドウがどれだけスクロールされたかを調べ、スクロール量を変数valueにバインドしています。


    if ( value > navPos ) {
     $nav.addClass(fixedClass);
     $main.css('margin-top', navHeight);
   } else {
     $nav.removeClass(fixedClass);
     $main.css('margin-top', '0');
   }

valueとnavPosを比較して条件分岐していますが、日本語に変換するとこうなります。

もし(スクロール量が<nav>の初期位置よりスクロールされたら)
<nav>にis-fixedというクラスをつける
<main>に<nav>と同じ高さ分のmargin-topをつける
そうじゃない場合は・・
<nav>からis-fixedというクラスを削除する
<main>のmargin-topを0にする


offset().top,やscrollTop()の意味がわかれば簡単ですね。

あとはCSSでクラスをつけたり外したりするだけで結構簡単にできてしまいます。


これを応用すれば、他にもいろんなパターンのスティッキーヘッダーが実装できるので、ご紹介します。


パターン2:デザインの変更


これもよくあるUI。

ヘッダーの高さが変わったり、背景色や文字色が変わったりする動きは、結構よく遭遇します。


header {
 position: fixed;
 top: 0;
 left: 0;
 z-index: 2;
 width: 100%;
 height: 120px;
 padding:20px;
 text-align: center;
 background-color: #EAB543;
 transition: .3s;
}
header h1 {
 color: #333;
 transition: .3s;
}
.is-fixed {
 position: fixed;
 top: 0;
 left: 0;
 z-index: 2;
 width: 100%;
}

.is-animation {
 background-color: rgba(0, 0, 0, 0.7);
 height: 90px;
 padding:5px;
}
.is-animation h1 {
 color: #fff;
}
.is-animation nav ul li a {
 color: #fff;
}


$(function() {
     var $win = $(window),
         $header = $('header'),
         animationClass = 'is-animation';
     $win.on('load scroll', function() {

       var value = $(this).scrollTop();
       if ( value > 100 ) {
         $header.addClass(animationClass);
       } else {
         $header.removeClass(animationClass);
       }
     });
   });


基本的には①と変わらず、クラスの付け替えで操作しています。


パターン3:途中から表示


ぬぬ、、ちょっとややこしくなってきました。。

jQueryのclone()メソッドを使って、body内にナビゲーションを複製し、それを改めて表示させています。


CSS

.clone-nav {
   position: fixed;
   top: 0;
   left: 0;
   z-index: 2;
   width: 100%;
   transition: .3s;
   transform: translateY(-100%);
 }

 .is-show {
   transform: translateY(0);
 }


jQuery

$(function() {
   var $win = $(window),
       $cloneNav = $('nav').clone().addClass('clone-nav').appendTo('body'),
       showClass = 'is-show';
 
   $win.on('load scroll', function() {
     var value = $(this).scrollTop();
     if ( value > 700 ) {
       $cloneNav.addClass(showClass);
     } else {
       $cloneNav.removeClass(showClass);
     }
   });
 });


パターン4:フッター手前で非表示


フッター手前で非表示にする方法です。

これまでの応用になるので、ちょっと考えれば実装できるかと思います。


ざっくり書くと、

・スクロール量を監視
・(サイト全体の高さースクロール量)がフッターの高さになった時
・ヘッダーを非表示にする

こんな流れです。

CSS

header {
 position: fixed;
 top: 0;
 left: 0;
 z-index: 2;
 width: 100%;
 height: 120px;
 padding:20px;
 text-align: center;
 background-color: #EAB543;
 transition: .3s;
}
header h1 {
 color: #333;
 transition: .3s;
}

.is-animation {
 background-color: rgba(0, 0, 0, 0.7);
 height: 90px;
 padding:5px;
}
.is-animation h1 {
 color: #fff;
}
.is-animation nav ul li a {
 color: #fff;
}


nav ul{
 display: flex;
 justify-content: center;
}
nav ul li a{
 color:#333;
 font-size:24px;
 text-decoration: none;
 transition: all 0.4s;
}
nav ul li a:not(last-child){
 margin-right:30px;
}
nav ul li a:hover{
 border-bottom:2px solid azure;
 opacity: 0.7;
}
main{
 background-color: #FD7272;
 height: 4000px;
 transition: all 0.8s;
}
footer{
 background-color: #2C3A47;
 height: 100px;
}


.is-fixed {
 position: fixed;
 top: 0;
 left: 0;
 z-index: 2;
 width: 100%;
}
.is-hide {
 transform: translateY(-100%);
}


jQuery

$(function() {
 var $win = $(window),
     $header = $('header'),
     $main = $('main'),
     animationClass = 'is-animation';

 $win.on('load scroll', function() {
   var value = $(this).scrollTop();
   if ( value > 100 ) {
     $header.addClass(animationClass);
   } else {
     $header.removeClass(animationClass);
   }
 });

     navHeight = $header.outerHeight(),
     footerHeight = $('footer').outerHeight(),
     documentHeight = $(document).height(),
     navPos = $header.offset().top,
     fixedClass = 'is-fixed',
     hideClass = 'is-hide';

   $win.on('load scroll', function() {
   var value = $(this).scrollTop(),
   scrollPos = $win.height() + value;

   if ( value > navPos ) {
     if ( documentHeight - scrollPos < footerHeight ) {
       $header.addClass(hideClass);
     } else {
       $header.removeClass(hideClass);
     }
     $header.addClass(fixedClass);
     $main.css('margin-top', navHeight);
   } else {
     $header.removeClass(fixedClass);
     $main.css('margin-top', '0');
   }
 });
});


もう大丈夫ですね。


まとめ

今回はスティッキーヘッダーについてまとめました。

ここまでできたら、しばらくスティッキーヘッダーに困ることはなさそう。


jQueryで作るよくあるUIは、忘備録も兼ねてこのマガジンにまとめておきたいと思います。

サポートいただければ嬉しいです。