DEMO
下へスクロールすると、右下に「トップへ戻る」ボタンが現れます。
ここが記事の末尾です。
CODE
<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>
.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; }
}
(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
少しスクロールすると右下に現れる「ページトップへ戻る」ボタンを作って。スクロール量が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
※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。
学びを止めない · AMAZONサブスク
※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。
長いページを読み進めたあと、ワンタップで先頭へ戻れるボタンです。スマホではページの先頭へ戻る操作が思いのほか手間になるため、ブログ・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プロンプトは、クレジット表記なしで自由に使えます。コピーしてそのままプロジェクトに利用できます。