No.144
SCROLL CSSJS

Back to Top Button

少しスクロールすると現れ、読んだ割合をリングで示す「ページトップへ戻る」ボタン。conic-gradient とカスタムプロパティで進捗を描き、押すと先頭まで滑らかに戻ります。

DEMO

記事タイトル

下へスクロールすると、右下に「トップへ戻る」ボタンが現れます。

ここが記事の末尾です。

CODE

HTML
<div class="demo-stage btt-stage">
  <div class="btt-wrap">
    <div class="btt-scroller" id="btt-scroller" tabindex="0" aria-label="スクロールできる記事のデモ">
      <h3 class="btt-h">記事タイトル</h3>
      <p class="btt-p">下へスクロールすると、右下に「トップへ戻る」ボタンが現れます。</p>
      <div class="btt-line"></div><div class="btt-line"></div><div class="btt-line btt-short"></div>
      <div class="btt-line"></div><div class="btt-line"></div><div class="btt-line btt-short"></div>
      <div class="btt-line"></div><div class="btt-line"></div><div class="btt-line btt-short"></div>
      <div class="btt-line"></div><div class="btt-line"></div><div class="btt-line btt-short"></div>
      <div class="btt-line"></div><div class="btt-line"></div><div class="btt-line btt-short"></div>
      <p class="btt-p">ここが記事の末尾です。</p>
    </div>
    <button type="button" class="btt-btn" id="btt-btn" aria-label="ページの先頭へ戻る">
      <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 19V5M5.5 11.5L12 5l6.5 6.5"/></svg>
    </button>
  </div>
</div>
CSS
.btt-stage { display:flex; align-items:center; justify-content:center; padding:1.5rem; background:#0B0B10; min-height:300px; }
.btt-wrap { position:relative; width:100%; max-width:420px; }
.btt-scroller { height:260px; overflow-y:auto; padding:1.2rem 1.4rem; box-sizing:border-box; background:#15151B; border:1px solid rgba(255,255,255,.1); border-radius:14px; }
.btt-scroller:focus-visible { outline:2px solid #E91B89; outline-offset:3px; }
.btt-h { margin:0 0 .6rem; color:#fff; font-family:'Oswald',sans-serif; letter-spacing:.06em; }
.btt-p { margin:.4rem 0 1rem; color:#9A9AA6; font-size:.85rem; }
.btt-line { height:10px; margin:0 0 .7rem; border-radius:4px; background:rgba(255,255,255,.1); }
.btt-short { width:60%; margin-bottom:1.4rem; }
.btt-btn {
  --p: 0;
  position:absolute; right:14px; bottom:14px; width:46px; height:46px; border:0; border-radius:50%; cursor:pointer;
  background: radial-gradient(closest-side, #1E1E26 82%, transparent 84% 100%), conic-gradient(#E91B89 calc(var(--p) * 1%), rgba(255,255,255,.14) 0);
  color:#fff; display:flex; align-items:center; justify-content:center;
  opacity:0; transform:translateY(12px) scale(.9); pointer-events:none;
  transition: opacity .25s ease, transform .25s cubic-bezier(.22,1,.36,1);
}
.btt-btn.is-on { opacity:1; transform:none; pointer-events:auto; }
.btt-btn:hover svg { transform:translateY(-2px); }
.btt-btn:focus-visible { outline:2px solid #E91B89; outline-offset:3px; }
.btt-btn svg { width:18px; height:18px; fill:none; stroke:currentColor; stroke-width:2.2; stroke-linecap:round; stroke-linejoin:round; transition: transform .2s ease; }
@media (prefers-reduced-motion: reduce) {
  .btt-btn, .btt-btn svg { transition-duration:.01ms; }
}
JS
(function(){
  var sc = document.getElementById('btt-scroller');
  var btn = document.getElementById('btt-btn');
  if (!sc || !btn) return;
  var reduce = window.matchMedia('(prefers-reduced-motion: reduce)');
  var ticking = false;
  function update(){
    ticking = false;
    var max = sc.scrollHeight - sc.clientHeight;
    var p = max > 0 ? Math.round(sc.scrollTop / max * 100) : 0;
    btn.style.setProperty('--p', p);
    btn.classList.toggle('is-on', sc.scrollTop > 80);
  }
  sc.addEventListener('scroll', function(){ if (!ticking) { ticking = true; requestAnimationFrame(update); } }, { passive: true });
  btn.addEventListener('click', function(){
    sc.scrollTo({ top: 0, behavior: reduce.matches ? 'auto' : 'smooth' });
    sc.focus({ preventScroll: true });
  });
  update();
})();

AI PROMPT

Claude Code Cursor v0
PROMPT
少しスクロールすると右下に現れる「ページトップへ戻る」ボタンを作って。スクロール量が80pxを超えたら opacity と translateY(12px) scale(.9) から現れ、先頭付近では消えて pointer-events: none にする。ボタンの外周に読んだ割合を示すリングを付ける:カスタムプロパティ --p(0〜100)を JS で更新し、background に conic-gradient(アクセント色 calc(var(--p) * 1%), 薄い色 0) と、中央を塗りつぶす radial-gradient を重ねると、画像もSVGも使わずに進捗リングになる。scroll イベントは requestAnimationFrame で間引き、passive: true を付ける。クリックで scrollTo({ top: 0, behavior: 'smooth' }) を呼ぶが、prefers-reduced-motion: reduce の時は behavior: 'auto' にすること。戻ったあとはスクロール領域の先頭へフォーカスを移し、キーボード利用者が迷わないようにする。ボタンには aria-label="ページの先頭へ戻る" を付ける。

Acceptance criteria: works with prefers-reduced-motion (animation disabled), zero console errors, zero layout shift

AIエージェントでの実装ガイド → Claude Code でWebアニメーションを実装する

BOOKS · PR · AMAZON

📖 なかしまぁ先生のCSSアニメーション入門 📖 UIデザインの教科書 新版 マルチデバイス時代のインターフェース設計 📖 Fundamentals of Web Animation with GSAP

※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。

学びを止めない · AMAZONサブスク

📚 Kindle Unlimited — 技術書・デザイン書が読み放題。30日無料体験 → 🎧 Audible — 移動中に耳で学ぶオーディオブック。30日無料体験 → 📦 Amazon Prime — Prime Reading・配送特典つき。30日無料体験 → 🎵 Music Unlimited — 作業用BGMに。1億曲が聴き放題・30日無料体験 →

※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。

RELATED EFFECTS

↗ MORE
→ SCROLL PROGRESS BAR → PROGRESS RING → SCROLL-DRIVEN PROGRESS

Back to Top Button(ページトップへ戻るボタン)とは

長いページを読み進めたあと、ワンタップで先頭へ戻れるボタンです。スマホではページの先頭へ戻る操作が思いのほか手間になるため、ブログ・ECの商品一覧・ドキュメントサイトで広く使われています。

当サイトの Scroll Progress Bar は画面上端の横棒で読了率を示す演出、Progress Ring は進捗そのものを円で表す部品です。本ページは「戻る」という操作のためのボタンに、読んだ割合を重ねて表示する別テーマで、ボタンの見た目だけで現在位置も伝えられます。

先頭付近では隠し、スクロールしてから出すのが基本です。最初から出ていると押す理由がなく、画面の端を常に占有するだけになります。表示のしきい値と、戻ったあとのフォーカスの行き先を決めておくと、キーボードでも迷わない部品になります。

よくある質問

進捗リングを SVG ではなく conic-gradient で描く理由は?

conic-gradient はカスタムプロパティ1つで角度を変えられるため、JavaScriptからは --p の数値を更新するだけで済みます。SVG の stroke-dashoffset でも作れますが、円周の長さを計算する処理が要ります。中央を radial-gradient で塗りつぶせば、背景指定だけでドーナツ型のリングになります。

ページ全体に使う場合はどう変えればよいですか?

スクロール領域を window にし、scrollTop を window.scrollY、最大値を document.documentElement.scrollHeight - innerHeight に置き換えます。ボタンは position: fixed で右下に固定しますが、広告やチャットボタンと重ならない位置と、スマホで親指が届く大きさ(44px以上)を確認してください。

コードは無料で使えますか?

はい。Motion LabのコードスニペットとAIプロンプトは、クレジット表記なしで自由に使えます。コピーしてそのままプロジェクトに利用できます。