下スクロールで消える・上スクロールで現れる素の JavaScript

固定ヘッダーやナビを下スクロール時に隠し、上スクロール時に表示する方法

Akira

福岡在住ウェブデザイナー。Web サイト制作に役立つ情報を「見やすさ」と「使いやすさ」にこだわり紹介しています。

サイト上部に固定したヘッダーやナビなどが、下にスクロールすると消え、上にスクロールすると現れる実装方法のご紹介です。

jQuery を使わず素の JavaScript で、かつ window.requestAnimationFrame() メソッドを使います。

サイトが遅く重くならず、スピードが犠牲になりません。また、スムーズなアニメーションを表現できます。

実際の動作は、当サイトの上部にある検索フォームでご確認いただけます。ただし、 AMP では動作しません。

HTML

今回は、ヘッダーを例とします。

HTML は、非常に単純なものです。

<header id="header">サイト名などを書く</header>

requestAnimationFrame() を使った JavaScript

次は JavaScript です。 requestAnimationFrame() を使い、スクロールイベントを設定します。

( function() {
    const target     = document.getElementById( 'header' ),
          height     = 56;
    let offset       = 0,
        lastPosition = 0,
        ticking      = false;
    
    function onScroll() {
        if( lastPosition > height ) {
            if( lastPosition > offset ) {
                target.classList.add( 'head-animation' );
            } else {
                target.classList.remove( 'head-animation' );
            }
            offset = lastPosition;
        }
    }
    
    window.addEventListener( 'scroll', function(e) {
        lastPosition = window.scrollY;
        
        if( !ticking ) {
            window.requestAnimationFrame( function() {
                onScroll( lastPosition );
                ticking = false;
            });
            ticking = true;
        }
    });
})();

コードをご説明します。

2 行目 : const target = document.getElementById( 'header' ),

2 行目には、対象の要素の id を指定します。今回は <header> の id を指定しています。

3 行目 : height = 56;

3 行目は、対象の要素が隠れ始める位置の指定です。 56 であれば、サイトの上部から 56px スクロールした地点から要素が隠れます。

0 の指定も可能ですが、アニメーションが性急に感じるかもしれません。対象の要素の高さと同じ値の指定がおすすめです。

また、下にスクロールしても、ある程度の位置まで要素を隠したくない場合があります。その場合には、 400 など少し多めの任意の値を指定します。

11 行目 : target.classList.add( 'head-animation' );

8 行目から 17 行目は、スクロール時の処理の設定です。

そのうち 11 行目で、下にスクロールしている時に、対象の要素の class に head-animation を追加しています。

13 行目 : target.classList.remove( 'head-animation' );

13 行目で、上にスクロールしている時は、対象の要素の class から head-animation を削除しています。

15 行目 : offset = lastPosition;

15 行目は、スクロール量の更新です。この設定がなければ、アニメーションが動きません。

19 行目から 29 行目は、 requestAnimationFrame() の設定です。 MDN のやり方をそのまま真似ています。元ネタの「 Leaner, Meaner, Faster Animations with requestAnimationFrame 」で、スクロールイベントをそのまま使うべきではない理由をご覧いただけます。

transform で動きをつける CSS

あとは CSS を指定すれば完成します。

#header {
  background: #fff;
  box-shadow: 0 4px 8px -3px rgba(17, 17, 17, .06);
  height: 56px;
  position: fixed;
  top: 0;
  transition: .3s cubic-bezier(.4, 0, .2, 1);
  width: 100%;
  z-index: 199999;
}

.head-animation {
  transform: translateY(-100%);
}

対象の要素に position: fixed;top: 0; を指定し、サイト上部に固定します。

そして、 JavaScript で追加する head-animation に、 transform: translateY(-100%); を指定します。これで下にスクロール時は、対象の要素が上に消えていきます。

要素の高さを使った top: -56px; でも同じ表現はできますが、 GPU アクセラレーションが可能な transform での指定がおすすめです。アニメーションが、より滑らかになります。


jQuery は便利ですが、サイトが遅くなりがちです。

また、単にスクロールイベントを使ってしまうと、ブラウザにひどい負荷をかけ、サイトが重くなります。

ご紹介した JavaScript は、サイト速度を犠牲にしない上に、ブラウザの負荷を軽減できる方法です。