jQueryでアンカーリンクのスムーズスクロールを実装する完全ガイド|固定ヘッダー対応・easing付き

jQuery

ページ内リンク(アンカーリンク)をクリックしたとき、指定セクションへスムーズにスクロールする実装はWebサイトのUXを大きく向上させます。本記事ではjQueryの animate() を使った基本実装から、固定ヘッダーのオフセット補正・easing設定・バニラJS代替まで体系的に解説します。

この記事でわかること

  • アンカーリンク全体をスムーズスクロールにする方法
  • 固定ヘッダーがある場合のオフセット補正
  • スクロール速度・easingのカスタマイズ
  • URLハッシュを変えずにスクロールする方法
  • CSSのscroll-behaviorによるjQuery不要の代替手段
スポンサーリンク

1. 基本実装:すべてのアンカーリンクをスムーズに

ページ内の全アンカーリンク(href="#...")をjQueryで一括処理します。

$(function () {
  $('a[href^="#"]').on('click', function (e) {
    e.preventDefault();
    var target = $(this.hash);  // href='#section1' → '#section1' の要素
    if (!target.length) return;

    $('html, body').animate(
      { scrollTop: target.offset().top },
      600  // スクロール時間(ms)
    );
  });
});
$(“html, body”) と両方指定する理由
ブラウザによってスクロール可能な要素が html または body のどちらかです。両方を指定することで Chrome・Firefox・Safari・IE すべてで動作します。

2. 固定ヘッダーがある場合のオフセット補正

固定ヘッダーがあるとリンク先の見出しがヘッダーの下に隠れてしまいます。ヘッダーの高さ分を引き算することで正確な位置に移動できます。

$(function () {
  $('a[href^="#"]').on('click', function (e) {
    e.preventDefault();
    var target  = $(this.hash);
    if (!target.length) return;

    var headerH = $('header').outerHeight() || 0;  // ヘッダー高さを取得
    var margin  = 16;  // 追加の余白(px)
    var pos     = target.offset().top - headerH - margin;

    $('html, body').animate({ scrollTop: pos }, 500);
  });
});
ヘッダー高さは動的取得が確実
$("header").outerHeight() はパディングを含む外側の高さを返します。ハードコードではなく動的取得にするとレスポンシブでヘッダー高さが変わっても正確に動作します。

3. スクロール速度とeasingのカスタマイズ

animate() の第2・3引数でスクロールの速さとイージングを変えられます。

// 数値(ミリ秒)または文字列キーワードで速度指定
$('html, body').animate({ scrollTop: pos }, 300);          // 速め
$('html, body').animate({ scrollTop: pos }, 800);          // 遅め
$('html, body').animate({ scrollTop: pos }, 'slow');       // 約 600ms
$('html, body').animate({ scrollTop: pos }, 'fast');       // 約 200ms

// easing(jQuery UI が必要)
$('html, body').animate({ scrollTop: pos }, 600, 'easeInOutQuart');

// コールバック: スクロール完了後に実行
$('html, body').animate({ scrollTop: pos }, 600, function () {
  console.log('スクロール完了');
});
jQueryデフォルトのeasing
jQuery標準は swing(少しゆっくり始まりゆっくり終わる)と linear(一定速度)のみ。easeInOutQuart などは jQuery UI またはjquery.easing.jsが必要です。

4. URLハッシュを変更せずにスクロール

デフォルトでは e.preventDefault() でURLハッシュの変更は防げています。ただし履歴に残したい場合は history.pushState() を組み合わせます。

$('a[href^="#"]').on('click', function (e) {
  e.preventDefault();
  var target  = $(this.hash);
  if (!target.length) return;

  var headerH = $('header').outerHeight() || 0;
  var pos     = target.offset().top - headerH - 16;

  $('html, body').animate({ scrollTop: pos }, 500, function () {
    // スクロール完了後にURLハッシュを更新(履歴に追加)
    history.pushState(null, null, '#' + target.attr('id'));
  });
});

5. 特定のリンクのみスムーズスクロール対象にする

ページ内リンク全体ではなく、特定のナビゲーション内のリンクのみを対象にする例です。

// .page-nav 内のリンクのみ
$('.page-nav a[href^="#"]').on('click', function (e) { ... });

// data-scroll 属性を持つリンクのみ
$('a[data-scroll]').on('click', function (e) { ... });

// 特定の href を除外(#top はスムーズスクロール不要など)
$('a[href^="#"]:not([href="#top"])').on('click', function (e) { ... });

6. バニラJSとCSSによる代替実装

モダンなブラウザではjQuery不要でスムーズスクロールが実現できます。

/* CSSだけでアンカーリンクをスムーズに(IE非対応) */
html {
  scroll-behavior: smooth;
}

CSSだけでは固定ヘッダーのオフセット補正ができません。その場合は scroll-padding-top を使います。

html {
  scroll-behavior: smooth;
  scroll-padding-top: 80px;  /* ヘッダー高さ分 */
}

バニラJSでの実装:

document.querySelectorAll('a[href^="#"]').forEach(function (anchor) {
  anchor.addEventListener('click', function (e) {
    e.preventDefault();
    var target = document.querySelector(this.getAttribute('href'));
    if (!target) return;

    var headerH = document.querySelector('header').offsetHeight;
    var pos     = target.getBoundingClientRect().top + window.scrollY - headerH - 16;

    window.scrollTo({ top: pos, behavior: 'smooth' });
  });
});

7. 実装方法の比較

方法 コード量 固定ヘッダー補正 IE対応 速度調整
jQuery animate() 自由
CSS scroll-behavior 最少 scroll-padding-topで対応 非対応 不可
バニラJS scrollTo() 非対応 smooth固定

まとめ

jQueryでのスムーズスクロール実装は $("a[href^=\"#\"]").on("click", ...) で全アンカーを一括処理するのが基本です。固定ヘッダーがある場合は outerHeight() で高さを取得してオフセット補正を忘れずに行いましょう。モダン環境では CSS の scroll-behavior: smooth + scroll-padding-top の組み合わせが最もシンプルです。

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

よくある質問(FAQ)

Q固定ヘッダーがある場合、リンク先が隠れてしまいます
Aヘッダーの高さ分を offset().top から引き算します。var pos = target.offset().top - $("header").outerHeight() - 余白px; のように計算してください。CSSのみで解決するなら scroll-padding-top も有効です。
Qスクロールが途中で止まる・動かない
Aセレクタが間違っていないか確認してください。また $("html, body") と両方指定すると ブラウザ互換性が上がります。href属性と対応するidが一致しているかも確認しましょう。
QjQuery不要でスムーズスクロールできますか?
ACSSで html { scroll-behavior: smooth; } を指定するだけでアンカーリンクがスムーズになります(IE非対応)。固定ヘッダー対応は scroll-padding-top を追加してください。
Qスクロール完了後に処理を実行したい
Aanimate() の第3引数にコールバック関数を渡します。$("html, body").animate({scrollTop: pos}, 500, function(){ /* 完了後の処理 */ });
QURLのハッシュを変えたくない(履歴に残したくない)
Ae.preventDefault() でデフォルトのリンク動作を防ぐことでURLハッシュは変更されません。意図的にURLを更新したい場合はスクロール完了後に history.pushState() を呼びます。