ページ内リンク(アンカーリンク)をクリックしたとき、指定セクションへスムーズにスクロールする実装は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 のどちらかです。両方を指定することで 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標準は
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)
offset().top から引き算します。var pos = target.offset().top - $("header").outerHeight() - 余白px; のように計算してください。CSSのみで解決するなら scroll-padding-top も有効です。$("html, body") と両方指定すると ブラウザ互換性が上がります。href属性と対応するidが一致しているかも確認しましょう。html { scroll-behavior: smooth; } を指定するだけでアンカーリンクがスムーズになります(IE非対応)。固定ヘッダー対応は scroll-padding-top を追加してください。animate() の第3引数にコールバック関数を渡します。$("html, body").animate({scrollTop: pos}, 500, function(){ /* 完了後の処理 */ });e.preventDefault() でデフォルトのリンク動作を防ぐことでURLハッシュは変更されません。意図的にURLを更新したい場合はスクロール完了後に history.pushState() を呼びます。

