【JavaScript】アンカーリンクのスムーススクロールを実装する方法

【JavaScript】アンカーリンクのスムーススクロールを実装する方法 JavaScript

ページ内のセクションへ移動するアンカーリンク(# リンク)を、カクッと飛ぶのではなくスーッとスクロールさせる方法を解説します。実は、まずはCSSだけで実装できます。

この記事の結論:一番簡単なのはCSSの scroll-behavior: smooth(JS不要)。固定ヘッダーで位置がずれるならscroll-margin-topで調整します。クリックを細かく制御したいときだけ、JavaScriptの scrollIntoView /scrollTo を使います。
スポンサーリンク

完成イメージ(動くデモ)

↓ 上のボタンを押すと、枠内の対応するセクションへスーッとスクロールします:



セクション1
セクション2
セクション3

このデモは枠(コンテナ)に scroll-behavior: smooth を付け、ボタンで scrollTo しています。ページ全体のアンカーリンクなら、次のCSSだけで同じ効果が得られます。

最も簡単:CSSの scroll-behavior(JS不要)

htmlscroll-behavior: smooth を指定するだけで、ページ内のすべてのアンカーリンクがスムーススクロールになります。JavaScriptは不要です。

CSS:これだけでスムーススクロール
html {
  scroll-behavior: smooth;
}

固定ヘッダーがあって移動先がヘッダーに隠れる場合は、移動先の要素に scroll-margin-top を付けるだけで余白を確保できます。

CSS:固定ヘッダー分の余白(scroll-margin-top)
/* 移動先のセクションに付ける */
.section {
  scroll-margin-top: 60px; /* ヘッダーの高さ分 */
}

CSSの scroll-behavior の詳細はscroll-behaviorでスムーズスクロールを実装する方法で解説しています。多くのサイトはこれだけで十分です。

JavaScriptで実装する:scrollIntoView

クリック時に追加の処理を入れたい(メニューを閉じる、URLを更新するなど)場合は、JavaScriptで制御します。a[href^="#"] のクリックを拾い、scrollIntoView({ behavior: "smooth" }) でスクロールします。

JavaScript:scrollIntoViewでスムーススクロール
document.querySelectorAll('a[href^="#"]').forEach((link) => {
  link.addEventListener("click", (e) => {
    const id = link.getAttribute("href").slice(1);
    const target = document.getElementById(id);
    if (!target) return;

    e.preventDefault(); // 既定のジャンプを止める
    target.scrollIntoView({ behavior: "smooth", block: "start" });
  });
});

JavaScriptで preventDefault() すると、URLのハッシュ(#section)が更新されません。戻るボタンや共有に対応させたいなら、スクロール後に history.pushState でハッシュを書き換えます。

JavaScript:スクロール後にURLハッシュも更新
target.scrollIntoView({ behavior: "smooth", block: "start" });

// 戻る/共有に対応:URLのハッシュを更新(履歴に積む)
history.pushState(null, "", "#" + id);

固定ヘッダーのオフセット調整:scrollTo

JavaScript側で位置を細かく調整したいなら window.scrollTo を使います。要素の位置に window.scrollY を足し、ヘッダーの高さ分を引きます。

JavaScript:ヘッダー分ずらしてスクロール
const HEADER = 60; // 固定ヘッダーの高さ

const top = target.getBoundingClientRect().top + window.scrollY - HEADER;
window.scrollTo({ top, behavior: "smooth" });

scrollToscrollIntoView の違いや、任意の位置へスクロールする方法は特定の位置までスクロールする方法(scrollTo・scrollIntoView)で詳しく解説しています。

prefers-reduced-motionに配慮する

動きが苦手なユーザーのために、OSで「視差効果を減らす」が有効なときはスムーススクロールを無効化すると親切です。CSSなら次のように書けます。

CSS:動きを減らす設定では即移動
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}
JSの場合:JavaScriptで scrollIntoView を使うときも、window.matchMedia("(prefers-reduced-motion: reduce)").matchestrue ならbehavior: "auto"(即移動)に切り替えると配慮できます。

よくある質問(FAQ)

Qアンカーリンクのスムーススクロールを実装するには?
A一番簡単なのはCSSの html { scroll-behavior: smooth; } です(JS不要)。JavaScriptなら、a タグの clickpreventDefault() し、対象要素に scrollIntoView({ behavior: "smooth" }) を呼びます。
Q固定ヘッダーで移動先が隠れるときは?
ACSSなら移動先の要素に scroll-margin-top: ヘッダー高さ を付けるのが簡単です。JavaScriptなら getBoundingClientRect().top + window.scrollY - ヘッダー高さ を計算してwindow.scrollTo を使います。
Qページ外からのハッシュリンクでもスムーススクロールするには?
ADOMContentLoadedlocation.hash を確認し、ハッシュがあれば対象要素に scrollIntoView({ behavior: "smooth" }) を呼びます。URLに #section が付いていても即ジャンプにならないよう制御できます。
QCSSとJavaScriptはどちらを使うべき?
A基本はCSSの scroll-behavior で十分です。クリック時にメニューを閉じる・URLを書き換えるなど追加処理が必要なときだけJavaScriptを使います。

まとめ

アンカーリンクのスムーススクロールは、まずCSSの scroll-behavior: smooth で実装するのが最も簡単です。固定ヘッダーのずれは scroll-margin-top で調整します。

クリック時に追加処理を入れたいときだけ、JavaScriptの scrollIntoViewscrollTo(オフセット調整)を使いましょう。prefers-reduced-motion への配慮も忘れずに。