【jQuery】スクロールで追従するヘッダーの実装完全ガイド|固定・縮小・上下スライドまで

jQuery

スクロールに応じてヘッダーを固定表示(追従)させる実装は、ユーザビリティを高める定番テクニックです。本記事では指定位置でfixedに切り替える基本実装から、ヘッダー縮小・上スクロール時のみ表示・モバイル対応まで、jQuery・バニラJS両方のコードで解説します。

この記事でわかること

  • スクロール量に応じてヘッダーをfixedに切り替える方法
  • 追従時にスムーズなトランジションを付ける方法
  • スクロールダウン時に隠れ、アップ時に現れるヘッダーの実装
  • 追従時にヘッダーを縮小する実装
  • コンテンツのズレ(ガタツキ)を防ぐ方法
スポンサーリンク

1. 基本実装:指定位置で追従開始

最もシンプルな追従ヘッダーです。スクロール量が一定値を超えたら .is-fixed クラスを付与してCSSで固定します。

HTML

<header class="site-header" id="site-header">
  <div class="header-inner">
    <div class="site-logo">サイト名</div>
    <nav class="header-nav">
      <ul>
        <li><a href="#">メニュー1</a></li>
        <li><a href="#">メニュー2</a></li>
        <li><a href="#">メニュー3</a></li>
      </ul>
    </nav>
  </div>
</header>
<div id="header-placeholder"></div>  <!-- コンテンツのガタツキ防止 -->

CSS

.site-header {
  background: #1e293b;
  padding: 20px;
  transition: box-shadow 0.3s, padding 0.3s;
}
.header-inner {
  display: flex;
  justify-content: space-between;
  align-items: center;
  max-width: 1200px;
  margin: 0 auto;
}
.site-logo {
  color: #fff;
  font-size: 22px;
  font-weight: bold;
}
.header-nav ul { display: flex; gap: 24px; list-style: none; }
.header-nav a { color: #cbd5e1; text-decoration: none; }
.header-nav a:hover { color: #fff; }

/* 追従時に付くクラス */
.site-header.is-fixed {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 999;
  box-shadow: 0 2px 12px rgba(0,0,0,0.25);
  animation: slideDown 0.3s ease forwards;
}
@keyframes slideDown {
  from { transform: translateY(-100%); }
  to   { transform: translateY(0); }
}

jQuery

$(function () {
  var $header      = $('#site-header');
  var $placeholder = $('#header-placeholder');
  var threshold    = 200;  // この位置を超えたら追従開始(px)

  $(window).on('scroll.fixedHeader', function () {
    var scrollTop = $(this).scrollTop();

    if (scrollTop > threshold) {
      if (!$header.hasClass('is-fixed')) {
        // ガタツキ防止: ヘッダーが fixed になる分の高さを確保
        $placeholder.height($header.outerHeight());
        $header.addClass('is-fixed');
      }
    } else {
      $header.removeClass('is-fixed');
      $placeholder.height(0);
    }
  });
});
コンテンツのガタツキを防ぐには placeholder が必要
position: fixed にするとヘッダーがドキュメントフローから外れ、その分コンテンツが上にずれます。同じ高さの #header-placeholder を使って隙間を補填することでガタツキを防げます。

2. 追従時にヘッダーを縮小する

大きなヘッダーが追従すると読みにくくなります。追従時にパディングとフォントサイズを縮小することで、コンテンツの視認性を確保します。

.site-header {
  padding: 20px;
  transition: padding 0.3s, font-size 0.3s, box-shadow 0.3s;
}
.site-header.is-fixed {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 999;
  padding: 10px 20px;  /* 縮小 */
  box-shadow: 0 2px 8px rgba(0,0,0,0.2);
}
.site-header.is-fixed .site-logo {
  font-size: 16px;  /* ロゴも縮小 */
}

3. 下スクロールで隠れ・上スクロールで現れるヘッダー

読み物コンテンツで使われるテクニックです。スクロールダウン中はヘッダーを非表示にし、アップ時のみ表示することでコンテンツを広く使えます。

$(function () {
  var $header    = $('#site-header');
  var lastScroll = 0;
  var threshold  = 80;   // ヘッダーの高さ程度

  $(window).on('scroll.smartHeader', function () {
    var currentScroll = $(this).scrollTop();

    if (currentScroll <= 0) {
      // 最上部: 常に表示
      $header.removeClass('is-hidden').addClass('is-fixed');
      return;
    }

    if (currentScroll > lastScroll && currentScroll > threshold) {
      // 下スクロール: ヘッダーを上に隠す
      $header.addClass('is-hidden');
    } else if (currentScroll < lastScroll) {
      // 上スクロール: ヘッダーを表示
      $header.removeClass('is-hidden');
    }

    lastScroll = currentScroll;
  });
});
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 999;
  transition: transform 0.35s ease;
}
.site-header.is-hidden {
  transform: translateY(-100%);  /* 上に隠す */
}

4. 閾値をヘッダー自身の高さに合わせる

スクロール開始の閾値をハードコードするとレスポンシブで崩れることがあります。ページロード時にヘッダー高さを動的に取得するのが確実です。

$(function () {
  var $header   = $('#site-header');
  var threshold = $header.outerHeight();  // ヘッダー高さを自動取得

  $(window).on('scroll', function () {
    $header.toggleClass('is-fixed', $(this).scrollTop() > threshold);
  });
});

5. バニラJSでの実装(IntersectionObserver)

jQuery不要のモダンな実装例です。IntersectionObserver を使うことで scroll イベントリスナーより効率的に実装できます。

const header   = document.getElementById('site-header');
const sentinel = document.getElementById('scroll-sentinel'); // ヘッダー直後に置く要素

const observer = new IntersectionObserver(([entry]) => {
  header.classList.toggle('is-fixed', !entry.isIntersecting);
}, { threshold: 0 });

observer.observe(sentinel);
scroll イベントは throttle を検討
jQuery の scroll イベントは高頻度で発火します。パフォーマンスが気になる場合は requestAnimationFrame や lodash の _.throttle で間引くか、IntersectionObserver に切り替えましょう。

6. jQueryとCSS position:stickyの比較

比較項目 jQuery fixed切替 CSS position:sticky
実装の複雑さ 中(JSが必要) 低(CSSのみ)
縮小・アニメ 自由にカスタム可 限定的
ガタツキ対策 placeholderが必要 不要
IE対応 jQuery版は対応 IE非対応
パフォーマンス scrollイベント負荷あり ブラウザ最適化済み
縮小・アニメーション不要ならposition:stickyが推奨
ヘッダーが常に追従するだけなら position: sticky; top: 0; をCSSに書くだけです。JavaScriptは一切不要でパフォーマンスも優れています。

7. よくあるトラブルと解決策

固定後にコンテンツが上にガタつく

ヘッダーと同じ高さの placeholder 要素をヘッダー直後に配置し、is-fixed 付与時にその高さをJSでセットしてください(セクション1のサンプル参照)。

追従ヘッダーがコンテンツの上に重なる

z-index の設定が必要です。モーダルやドロップダウンが表示されている場合はそちらの z-index をヘッダーより大きくしてください。

iOSでスクロール中に追従が遅れる

iOS Safari では慣性スクロール中にイベントが発火しないことがあります。CSS の position: sticky で代替できる場合はそちらを検討してください。

まとめ

追従ヘッダーの基本はスクロール量の監視と is-fixed クラスの付け外しです。ガタツキ防止の placeholder、縮小効果のトランジション、上スクロール時のみ表示するスマートヘッダーなど、要件に合わせて組み合わせてください。

関連記事: 追従ヘッダーの高さに合わせてアンカーリンクの移動先を調整する方法 / スムーズスクロール機能付きのトップに戻るボタンを作る

よくある質問(FAQ)

QjQueryを使わずに追従ヘッダーを作れますか?
Aはい。CSSの position: sticky; top: 0; を使うとJavaScript不要で追従ヘッダーが作れます。縮小やアニメーションが必要な場合は IntersectionObserver をバニラJSで使う方法があります。
Q追従ヘッダーがコンテンツと重なるのを防ぐには?
Aヘッダー直後に同じ高さの placeholder 要素を置き、position: fixed 切り替え時にJSでその高さをセットします。これでヘッダーがフローから外れた分の空白を補填できます。
Qスクロールダウン時にヘッダーを隠す実装はどうすればいいですか?
A直前のスクロール位置を変数に保存しておき、現在位置との差でスクロール方向を判定します。下向きなら transform: translateY(-100%)、上向きなら元に戻すCSSクラスを付け外しします。
Qスクロールの閾値はどう決めればいいですか?
A一般的にはヘッダーの高さと同じ値にすると自然です。$header.outerHeight() で動的に取得すると、レスポンシブでヘッダー高さが変わっても正確に動作します。
Q追従ヘッダーのトランジションをスムーズにするには?
ACSSで transition: transform 0.3s ease; を指定するか、@keyframes slideDown でスライドインアニメーションを付けます。jQueryの animate() よりCSSトランジションの方がパフォーマンスが優れています。