jQueryでスムーススクロール機能付きのトップに戻るボタンを作る完全ガイド

Webサイトに「ページトップへ戻る」ボタンを設置したいとき、jQueryを使えばスムーズなスクロールアニメーションと表示/非表示の切り替えを数十行で実装できます。本記事では基本の実装から、フェードアニメーション・スクロール連動・バニラJSとの比較まで丁寧に解説します。

この記事でわかること

  • クリックでページトップへスムーズスクロールする実装
  • スクロール量に応じてボタンを表示・非表示にする方法
  • CSS で矢印アイコンを描く方法(画像不要)
  • フェードイン/アウトアニメーションの追加方法
  • jQuery不要のモダンな代替実装との比較
スポンサーリンク

1. 最小構成の実装

まずはHTMLとjQueryだけで動く最小構成を作ります。

HTML

<a href="#" id="btn-top" aria-label="ページトップへ戻る">▲</a>

CSS

#btn-top {
  display: none;          /* 初期非表示 */
  position: fixed;
  right: 30px;
  bottom: 30px;
  width: 50px;
  height: 50px;
  line-height: 50px;
  text-align: center;
  background: #0284c7;
  color: #fff;
  border-radius: 50%;
  text-decoration: none;
  font-size: 20px;
  z-index: 999;
}
#btn-top:hover {
  background: #0369a1;
  transform: translateY(-3px);
  transition: all 0.2s;
}

jQuery

$(function () {
  // 300px スクロールしたらボタンを表示
  $(window).on('scroll', function () {
    if ($(this).scrollTop() > 300) {
      $('#btn-top').fadeIn(300);
    } else {
      $('#btn-top').fadeOut(300);
    }
  });

  // クリックでトップへスムーズスクロール
  $('#btn-top').on('click', function (e) {
    e.preventDefault();
    $('html, body').animate({ scrollTop: 0 }, 600);
  });
});

2. CSS矢印ボタンを作る(画像不要)

::before 疑似要素で矢印を描けば画像は不要です。背景色を変えるだけで簡単にカスタマイズできます。

<div id="btn-top-arrow" aria-label="ページトップへ戻る"></div>
#btn-top-arrow {
  display: none;
  position: fixed;
  right: 30px;
  bottom: 30px;
  width: 50px;
  height: 50px;
  background: rgba(2, 132, 199, 0.85);
  border-radius: 50%;
  cursor: pointer;
  z-index: 999;
  transition: background 0.2s, transform 0.2s;
}
#btn-top-arrow:hover {
  background: #0369a1;
  transform: translateY(-3px);
}
/* CSS で矢印(上向き三角) */
#btn-top-arrow::before {
  content: "";
  display: block;
  position: absolute;
  top: 18px;
  left: 14px;
  width: 18px;
  height: 18px;
  border-top: 3px solid #fff;
  border-left: 3px solid #fff;
  transform: rotate(45deg);
}
$(function () {
  $(window).on('scroll', function () {
    $('#btn-top-arrow').fadeToggle($(this).scrollTop() > 300);
  });

  $('#btn-top-arrow').on('click', function () {
    $('html, body').animate({ scrollTop: 0 }, 600);
  });
});
fadeToggle の第1引数に真偽値を渡すテクニック
fadeToggle(bool) は bool が true のとき fadeIn、false のとき fadeOut になります。条件分岐を1行に短縮できる実用的なパターンです。

3. スクロール量をプログレスバーで表示する

ページの読了率を示すプログレスバーをヘッダーに追加する実装です。読み物系のブログで効果的です。

<div id="scroll-progress"></div>
#scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 4px;
  width: 0%;
  background: linear-gradient(90deg, #0284c7, #38bdf8);
  z-index: 9999;
  transition: width 0.1s;
}
$(window).on('scroll', function () {
  var scrollTop  = $(this).scrollTop();
  var docHeight  = $(document).height() - $(this).height();
  var progress   = (scrollTop / docHeight) * 100;
  $('#scroll-progress').css('width', progress + '%');
});

4. スクロール速度をカスタマイズする

animate() の第2引数でアニメーション時間(ミリ秒)を調整できます。数値以外に "slow""fast" といった文字列も使えます。

// 遅め(800ms)
$('html, body').animate({ scrollTop: 0 }, 800);

// 速め(300ms)
$('html, body').animate({ scrollTop: 0 }, 300);

// キーワード指定
$('html, body').animate({ scrollTop: 0 }, 'slow');   // 約 600ms
$('html, body').animate({ scrollTop: 0 }, 'fast');   // 約 200ms

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

5. アンカーリンクをすべてスムーズスクロールにする

ページ内の # で始まるリンクをまとめてスムーズスクロールに変換する汎用コードです。

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

    var headerH = $('header').outerHeight() || 0; // 固定ヘッダー分を補正
    var position = target.offset().top - headerH - 16; // 16px 余白

    $('html, body').animate({ scrollTop: position }, 500);
  });
});
固定ヘッダーがある場合は必ずオフセット補正を
固定ヘッダーの高さ分だけ移動先がずれます。$("header").outerHeight() で取得した値を引き算することで正確な位置に遷移できます。

6. バニラJSとの比較

jQueryなしで同等の機能を実現する方法も紹介します。依存ライブラリを減らしたい場合や、モダンな構成では以下のバニラJSが推奨されます。

// CSS だけでアンカースムーズスクロール(最もシンプル)
// html { scroll-behavior: smooth; }

// バニラJS でトップへ戻る
document.getElementById('btn-top').addEventListener('click', function (e) {
  e.preventDefault();
  window.scrollTo({ top: 0, behavior: 'smooth' });
});

// スクロール量に応じて表示切替(IntersectionObserver 版)
const btn = document.getElementById('btn-top');
const sentinel = document.createElement('div');
sentinel.style.cssText = 'position:absolute;top:300px;height:1px;';
document.body.prepend(sentinel);

const obs = new IntersectionObserver(([entry]) => {
  btn.style.display = entry.isIntersecting ? 'none' : 'block';
});
obs.observe(sentinel);
比較項目 jQuery バニラJS
コード量 少ない やや多い
ライブラリ依存 jQuery必須 不要
スクロール速度調整 animate()で自由 CSSでEasing指定可
古いブラウザ対応 IE対応済み IE非対応
パフォーマンス 普通 高い

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

ボタンをクリックしても動かない

セレクタのIDやクラスが一致しているか確認してください。また、jQuery のロード前にスクリプトが実行されている場合は $(function(){...}) でラップします。

スクロールが途中で止まる

html または body のどちらかのみを対象にするとブラウザによって動作しないことがあります。$("html, body") と両方指定するのが安全です。

固定ヘッダーと重なってボタンが見えない

z-index を十分大きい値(999以上)に設定してください。ヘッダーの z-index より大きい必要があります。

モバイルでタップしてもスムーズスクロールにならない

一部のモバイルブラウザでは -webkit-overflow-scrolling: touch を設定したスクロール要素がある場合、animate が効かないことがあります。その場合は CSS の scroll-behavior: smooth を併用してください。

まとめ

jQueryでトップへ戻るボタンを実装する場合、animate({ scrollTop: 0 })fadeIn/fadeOut の組み合わせが基本パターンです。固定ヘッダーがある場合はオフセット補正を忘れずに行いましょう。モダンな環境ではCSSの scroll-behavior: smooth だけで代替できるケースも増えています。

関連記事: jQueryでアンカーリンクのスムーズスクロールを実装する方法 / 追従ヘッダーの高さに合わせてアンカーリンクの移動先を調整する方法

よくある質問(FAQ)

QjQuery不要でスムーズスクロールを実装するには?
ACSSで html { scroll-behavior: smooth; } を指定するだけでアンカーリンクがスムーズになります。トップへ戻るには window.scrollTo({ top: 0, behavior: "smooth" }) を使います。IE非対応ですが、現代のサイトでは十分です。
Qスクロール速度を変えるにはどうすればいいですか?
Aanimate({ scrollTop: 0 }, 速度) の第2引数を変えます。数値(ミリ秒)または "slow"/"fast" の文字列が使えます。600〜800ms が自然な速度感です。
Qページトップへ戻るボタンをフェードで表示したい
A$(window).scrollTop() > 300 の条件で fadeIn()/fadeOut() を呼ぶのが定番です。fadeToggle(bool) に真偽値を渡すと1行でまとめられます。
Qページ内リンクをすべてスムーズスクロールにするには?
A$("a[href^='#']").on("click", ...) でページ内の全アンカーリンクを一括処理できます。固定ヘッダーがある場合は header.outerHeight() 分を引いてオフセット補正してください。
Qスクロール量をプログレスバーで表示するには?
Aスクロール率を (scrollTop / (docHeight - windowHeight)) * 100 で計算し、固定位置の要素の width をCSSで変化させます。本記事のセクション3に完全なコードを掲載しています。