Scroll Progressバーの作り方【JavaScriptでスクロール進捗を見せるUI】

Scroll Progressのアイキャッチ画像

→ easingやスクロールに関係する基礎はこちら
#03 easing / cubic-bezier
#18 Progress Bar Animation

ページを読んでいるとき、上部に細いバーが伸びていくUIを見たことはないでしょうか。
あれが Scroll Progress です。

スクロール位置に応じて進捗が可視化されるので、ユーザーは「今どのくらい読んだか」を直感的に把握できます。特に、記事ページやドキュメントページのように縦長なコンテンツと相性が良いUIです。

今回は、JavaScriptでScroll Progressバーを作る基本実装を、できるだけシンプルに整理して紹介します。
HTML・CSS・JavaScriptをそのままコピペすれば動く形でまとめているので、まずは一度動かしてみてください。

1.Scroll Progressとは?

Scroll Progressは、ページ全体のうち、現在どこまでスクロールしたかをバーで示すUIです。

たとえば次のような場面で使いやすいです。

  • 記事ページの読了率を見せたいとき
  • 長い解説ページで現在位置をわかりやすくしたいとき
  • UIに少しだけ動きを加えて、読みやすさを上げたいとき

目立ちすぎないのに、あると便利なUIなので、比較的導入しやすいのもポイントです。

2.まずは完成形

今回作るのは、画面上部に固定された細いバーが、スクロールに応じて横に伸びるシンプルなパターンです。

  • ページの最上部では 0%
  • 一番下まで読むと 100%
  • スクロール位置に合わせてバー幅を更新

この仕組みだけでも、かなりそれっぽく見えます。

3.実装の考え方

Scroll Progressの考え方はとてもシンプルです。

必要なのは次の3つです。

  1. 現在どれだけスクロールしたかを取得する
  2. スクロール可能な全体量を求める
  3. 現在位置 ÷ 全体量 で進捗率を出す

式で書くとこうです。

progress = scrollTop / (documentHeight - windowHeight)

この値を 0〜1 の範囲で扱い、バーの幅に変換すれば完成です。

→ スムーズな値の変化はここで解説しています
#11 Interpolation

4.完全コピペで動くサンプル

以下のコードをそのまま保存すれば動きます。

HTML

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Scroll Progress Demo</title>
  <link rel="stylesheet" href="style.css" />
</head>
<body>
  <div class="progress-wrap">
    <div class="progress-bar" id="progressBar"></div>
  </div>

  <main class="container">
    <h1>Scroll Progress Demo</h1>
    <p>
      このページは、スクロール位置に応じて上部のプログレスバーが伸びるサンプルです。
      下へスクロールして挙動を確認してみてください。
    </p>

    <section>
      <h2>Section 1</h2>
      <p>Scroll Progressは、長い記事ページと相性が良いUIです。</p>
      <p>読者が「あとどれくらいで読み終わるか」を把握しやすくなります。</p>
      <p>ページ上部の細いバーだけでも、体験が少し整って見えます。</p>
    </section>

    <section>
      <h2>Section 2</h2>
      <p>実装の基本は、現在のスクロール位置を全体の高さで割ることです。</p>
      <p>JavaScriptでは scrollTop や scrollHeight、clientHeight を使います。</p>
      <p>比率が出せれば、width に反映するだけで見た目が完成します。</p>
    </section>

    <section>
      <h2>Section 3</h2>
      <p>記事、ドキュメント、利用規約、チュートリアルなどにも応用できます。</p>
      <p>色や高さを変えれば、ブランドに合わせた見せ方も可能です。</p>
      <p>派手な演出を入れなくても、使いやすさに直結しやすいUIです。</p>
    </section>

    <section>
      <h2>Section 4</h2>
      <p>今回は最小構成ですが、応用として数値表示や目次連動もできます。</p>
      <p>まずはシンプルに、確実に動く形を押さえるのがおすすめです。</p>
      <p>最後までスクロールして、バーが100%になることを確認してみてください。</p>
    </section>

    <section>
      <h2>Section 5</h2>
      <p>ダミーテキストです。スクロール量を増やすために少し長めにしています。</p>
      <p>ダミーテキストです。スクロール量を増やすために少し長めにしています。</p>
      <p>ダミーテキストです。スクロール量を増やすために少し長めにしています。</p>
      <p>ダミーテキストです。スクロール量を増やすために少し長めにしています。</p>
      <p>ダミーテキストです。スクロール量を増やすために少し長めにしています。</p>
      <p>ダミーテキストです。スクロール量を増やすために少し長めにしています。</p>
    </section>
  </main>

  <script src="script.js"></script>
</body>
</html>

CSS

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  font-family: sans-serif;
  line-height: 1.8;
  color: #1f2937;
  background: #f8fafc;
}

.progress-wrap {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 4px;
  background: rgba(0, 0, 0, 0.06);
  z-index: 9999;
}

.progress-bar {
  width: 0%;
  height: 100%;
  background: linear-gradient(90deg, #34d399, #10b981);
  transform-origin: left center;
  transition: width 0.08s linear;
}

.container {
  width: min(720px, calc(100% - 32px));
  margin: 0 auto;
  padding: 48px 0 120px;
}

h1 {
  margin-bottom: 16px;
  font-size: 32px;
  line-height: 1.3;
}

h2 {
  margin-top: 56px;
  margin-bottom: 16px;
  font-size: 24px;
}

p {
  margin: 0 0 16px;
}

JavaScript

const progressBar = document.getElementById("progressBar");

function updateScrollProgress() {
  const scrollTop = window.scrollY || document.documentElement.scrollTop;
  const scrollHeight = document.documentElement.scrollHeight;
  const clientHeight = document.documentElement.clientHeight;

  const scrollable = scrollHeight - clientHeight;

  if (scrollable <= 0) {
    progressBar.style.width = "0%";
    return;
  }

  const progress = (scrollTop / scrollable) * 100;
  progressBar.style.width = `${progress}%`;
}

window.addEventListener("scroll", updateScrollProgress);
window.addEventListener("resize", updateScrollProgress);
window.addEventListener("load", updateScrollProgress);

コードのポイント

ここでは、JavaScriptの処理をざっくり確認しておきます。

1. 現在のスクロール位置を取得する

const scrollTop = window.scrollY || document.documentElement.scrollTop;

これは、今どれだけ下にスクロールしたかを表します。

2. ページ全体の高さと画面の高さを使う

const scrollHeight = document.documentElement.scrollHeight;
const clientHeight = document.documentElement.clientHeight;
const scrollable = scrollHeight - clientHeight;

scrollHeight はページ全体の高さ、clientHeight は表示領域の高さです。
この差分が、実際にスクロールできる量になります。

3. 進捗率をバー幅に反映する

const progress = (scrollTop / scrollable) * 100;
progressBar.style.width = `${progress}%`;

進捗率をそのまま % にして、バーの横幅に使っています。
これだけで、スクロール量に応じてバーが伸びます。

5.Scrollイベントで更新する理由

今回のサンプルでは、scroll イベントが発生するたびに進捗を更新しています。

window.addEventListener("scroll", updateScrollProgress);

Scroll Progressは、ユーザーのスクロール操作に追従するUIなので、まずはこの方法がもっともわかりやすいです。

ただし、もっと凝った実装にしたい場合は、次のような工夫もできます。

  • requestAnimationFrame で更新タイミングを整える
  • transform: scaleX() を使って描画負荷を抑える
  • 特定のコンテンツ領域だけを対象にする

まずは基本形を理解してから、必要に応じて発展させるのがよいと思います。

→ より安定した更新処理はこちら
#08 ループ設計
#09 Fixed Time Step

6.もう少し実用寄りにするなら

実案件やブログで使うなら、次のような調整もよくあります。

バーを細くして目立ちすぎないようにする

.progress-wrap {
  height: 3px;
}

記事の邪魔をしないUIにしたいなら、かなり有効です。

幅ではなく transform を使う

.progress-bar {
  width: 100%;
  transform: scaleX(0);
}
progressBar.style.transform = `scaleX(${progress / 100})`;

この形にすると、場合によっては描画がより滑らかに見えることがあります。
とくにアニメーション系UIでは、width より transform を使う設計が好まれることもあります。

記事本文だけを対象にする

ページ全体ではなく、本文エリアの読み進み具合だけを測りたいケースもあります。
その場合は article 要素などの高さを基準に計算すると、より実用的です。

7.よくあるつまずき

バーが最後まで100%にならない

コンテンツの高さ取得や余白の影響で、計算がずれることがあります。
まずは今回のように document.documentElement.scrollHeight と clientHeight を使う基本形で確認するのがおすすめです。

ページが短すぎて変化しない

スクロール量がほとんどないページでは、進捗バーもほぼ動きません。
動作確認時は、ダミーの文章を増やして縦長ページにするとわかりやすいです。

スクロール時に少しカクつく

今回のサンプルはシンプルさ優先なので問題ありませんが、
より丁寧に作るなら次のような改善余地があります。

  • requestAnimationFrame を使う
  • transform ベースに切り替える
  • update処理を必要最小限にする

8.実験:Scroll Progressバーの伸び方を観察する

上部のバーが、スクロール位置に応じてどのように変化するかを確認してみましょう。
シンプルなUIですが、ページ全体の読了感がかなり変わることがわかります。

観察ポイント

  • スクロール開始直後からバーが少しずつ伸びるか
  • ページ終端でほぼ100%まで到達するか
  • バーの高さや色を変えると印象がどう変わるか
  • width 更新と transform 更新で体感差があるか

→ 他のUIモーションも見る
#20 Hover Animation
#23 Stagger Animation
#24 Scroll Reveal Animation

9.まとめ

Scroll Progressは、少ないコードで導入できて、体験を少し良くできるUIです。

今回のポイントは次の3つです。

  • スクロール位置を取得する
  • スクロール可能量で割って進捗率を出す
  • その値をバー幅に反映する

たったこれだけですが、長いページではかなり有効です。
まずは今回の基本形をそのまま動かして、必要に応じて色・高さ・対象範囲を調整してみてください。

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA