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

Akira

福岡在住ウェブデザイナー。Web サイト制作に役立つ情報を紹介しています。AMP が大好き。

FacebookTwitter で記事の更新をお知らせしています。

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

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

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

動作

実装後の動作は、このようなものです。サイト上部に、高さ 56px・背景色が赤のヘッダーを作っています。そのヘッダーが、下スクロール時に消え、上スクロール時に現れます。

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 を指定すれば完成します。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 で追加する class の head-animation に、transform: translateY(-100%); を指定します。これで下にスクロール時は、対象の要素が上に消えていきます。

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

コメント

  1. このページの方法で実装してみました。chrome、firefox、safari、edgeでは正しく動きますがIE11ではうまく動かないようです。

    このページからリンクされている参考サイト「jQuery不要!センスのいいナビゲーションをJSでサクッと実装する方法」も試してみましたがIEでは動作せず。
    「Hide/Show header on scroll down/up using pure javascript」のOptimazationの方をやってみましたがIEでは一応動作するもののIEの時だけ文字が重なってしまうバグが有るようです。

    バグなくIE11でもうまく実装する方法があれば教えていただけると嬉しいです。

  2. アドバイス通り修正するとIE11でも問題なく動作するようになりました。
    いろいろ試行錯誤してもうまくいかず困っていましたが助かりました。

    ありがとうございます。

  3. このページを見つけて参考にさせていただきました。
    上にスクロールする際に、表示されるまでのスクロール量を調整するにはどうしたらよいでしょうか?

    • JavaScript のコードのこの部分を…。

      } else {
        target.classList.remove('head-animation');
      }

      このように変更されるといけるはずです。

      }
      else if (lastPosition < (offset - 20) || lastPosition < 100) {
        target.classList.remove('head-animation');
      }

      表示されるまでのスクロール量は、20 の部分で調整できます(20 だと 20px より大きく上にスクロールしたら表示)。

送信に失敗しました

ボットと判定された可能性があります。

大変お手数をおかけしますが、以下の内容をご確認の上、再度のコメントの送信をお願い申し上げます。