ちいつる

スクロールアニメーション

スクロール進捗バー

ページ上部のバーが読み進めた割合を示す。長い記事で残量がわかって安心。

ENGLISH

Reading Progress Bar

  • JS
33スクロールアニメーション の一覧 →

プレビュー

スクロール

操作枠内をスクロールすると動きます。

使いどころ

長い記事や規約、チェックリストのように「あとどれくらいで終わるか」を知りたいページに向く。残量が見えると読み進める判断がしやすく、離脱を減らす効果が期待できる。ページ上部に固定した細いバーは、本文の邪魔をせずに情報を足せる数少ない手段でもある。一方で、1画面で収まるページや、スクロール量が短いページに置くとバーがほとんど動かず、あるいは一瞬で満タンになって意味をなさない。無限スクロールのページでも、全体量が確定しないため進捗として嘘をつくことになる。商品一覧のような「読み終える」概念がない画面も対象外で、そこで残量を示しても行動の助けにならない。設置するなら、記事の本文だけを基準にするか、少なくとも数画面ぶんの縦長ページに限る。

仕組み

古典的な実装は scroll イベントで scrollY をページ全体の高さから割り、バーの transform: scaleX() に反映する方法。width ではなく scaleX を動かすのが要点で、レイアウトを再計算させずコンポジタだけで描画できる。transform-origin: left を指定しないと中央から広がってしまうので忘れないこと。近年は CSS だけで完結する animation-timeline: scroll() が使え、JavaScript を1行も書かずに同じ表現ができる。対応していないブラウザではバーが動かないだけなので、@supports で分岐して従来の JavaScript 実装をフォールバックに置くと安全。進捗の分母は document.documentElement.scrollHeight からビューポートの高さを引いた値で、これを忘れると最後までスクロールしても100%に届かない。

実装の注意

JavaScript 実装で最も多い失敗は、scroll イベントで毎回レイアウトを読み直すこと。スクロール中に scrollHeight を参照すると強制的な再計算が走り、スクロールが引っかかるように感じられる。高さはリサイズ時にだけ測り直してキャッシュし、更新自体も requestAnimationFrame でまとめる。position: fixed のバーは iOS のアドレスバーの伸縮で位置がずれることがあり、sticky にするか、safe-area を考慮した配置にすると落ち着く。バーの高さを2〜4px程度に抑えないと本文の領域を削ってしまう。色は本文の文字色と競合しない彩度にし、背景(未読部分)と前景(既読部分)のコントラストを十分に取る。記事の途中に横スクロールする表や埋め込みがあると、そこで縦スクロールが止まって進捗も止まるため、「壊れている」と誤解されないよう本文の構造も見直したい。

アクセシビリティ

進捗バーは装飾ではなく状態の表示なので、本来は role="progressbar" と aria-valuenow が適切に見える。しかしスクロール位置は連続的に変わるため、値を更新し続けると支援技術が読み上げを繰り返してしまう。実用上は aria-hidden="true" にして支援技術から隠し、見出しの階層と目次で「どこまで来たか」を辿れるようにする方が使いやすい。スクリーンリーダーの利用者は見出し単位で移動するため、h2・h3 を正しく振ることが最も効く進捗の提示になる。prefers-reduced-motion では、バーの伸縮にトランジションをかけないようにする。スクロールに追従する要素に慣性のような遅れがあると、動きに敏感なユーザーには不快になりやすい。色だけに頼らない点も同様で、細いバー1本では見落とすユーザーがいるため、残り時間の目安(「読了 約5分」)を本文冒頭に添えると補完になる。

調整して使う

調整するのは太さ・色・基準範囲。太さは2〜4pxが標準で、それ以上だと本文の領域を削って邪魔になる。色はブランドカラーをそのまま使うと強すぎることがあり、彩度を落とすか不透明度を0.8前後にすると本文の邪魔をしない。未読部分は透明にしてバー自体を消すか、薄いグレーを敷いて全長を示すか選べる。全長が見えると残量が把握しやすく、消すと画面がすっきりする。進捗の基準を「ページ全体」ではなく「記事本文の要素」にすると、長いフッターやコメント欄の影響を受けず、本文を読み終えた時点で100%になる。本文要素の offsetTop と高さから割合を出す形に変えるだけで実現できる。

コード(コピーして使えます)

<div class="progress-bar"></div>
<div class="progress-body">
  <p>上部のバーがスクロール量を示します。</p>
  <div class="filler"></div>
  <p>最後まで来るとバーが満タンに。</p>
</div>

タグ

関連パーツ