ページの一番上に戻るボタンをCSSで作る|コピペで使える4種類と、置く・置かないの判断

ページの一番上に戻るボタン。置く・置かないの判断と、押しやすい大きさ

長いページを下まで読んだあと、画面の右下にある矢印のボタンを押すと、ページの先頭へすっと戻る。よく見かけるこの「トップへ戻るボタン」は、HTMLのリンク1つとCSSで作れます。基本の形なら、JavaScriptは要りません。

使いどころ

スマホで3〜4画面より長くなるページに置く。1〜2画面で終わるページや、右下にチャットや予約のボタンがすでにあるページには、固定のボタンを置かない。

今回は、右下の丸いボタン、スクロールしたら出てくるボタン、読んだ量が分かる輪っか付きのボタン、ページの終わりに置く文字のリンクの4種類を、コピペ用のコードつきで紹介します。あわせて、ボタンの大きさや、キーボード・読み上げでの使いやすさの確かめ方もまとめました。

トミー

連載「WEBの技術」の18回目です。
今回は「ページの一番上に戻るボタン」。小さな部品ですが、置くかどうかの判断まで見ていきます。

完成見本:下まで読んだら、ボタンで先頭へ

下の見本は、小さな画面の中を自動で下へスクロールさせ、最後に右下のボタンを押した形にして、先頭へ戻しています。灰色の線が本文の代わりです。

BASIC1. 右下の丸いボタン記事・サービス紹介など、縦に長いページ

※ 見本は見た目を見せるためのもので、読み上げソフトでは読まれないようにしています。見本の中では、ボタンを小さな画面の右下に置くため、position: fixed の代わりに absolute を使っています。端末の「動きを減らす」設定がオンのときは、自動では動きません。触っている間も止まります。

コピペ用のコード

HTMLは、ページの最後(</body> の前)か、本文のいちばん下に置きます。CSSは、サイトのCSSファイルや、WordPressならテーマの「追加CSS」などに入れます。JavaScriptを使う2と3は、</body> の前に <script> で入れます。クラス名の頭の kd-top は、サイトのほかのデザインと名前がぶつからないようにするための目印です。

WordPressのテーマには、「トップへ戻る」ボタンを最初から持っているものがあります。テーマの設定で出せる場合は、そちらを使うほうが、テーマの更新で崩れる心配が少なくなります。2つ置くと右下にボタンが重なるので、どちらか1つにします。

1. 右下の丸いボタン

いちばん基本の形です。リンクの行き先を #top にすると、JavaScriptなしでページの先頭へ戻れます。position: fixed で画面の右下に置き、html に scroll-behavior: smooth を書くと、ぱっと飛ばずに、なめらかに上へ戻ります。

HTML
<!-- ページの最後(</body> の前)に置く -->
<a class="kd-top-btn" href="#top" aria-label="ページの先頭へ戻る">
  <svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true">
    <path d="M6 15l6-6 6 6" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/>
  </svg>
</a>
CSS
/* ページ内リンクで、なめらかにスクロールさせる */
html {
  scroll-behavior: smooth;
}
/* 「動きを減らす」設定の人には、すぐ移動する */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}
.kd-top-btn {
  /* 画面の右下に置いたままにする */
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 100;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  color: #FFFFFF;
  background: #0284C7;
  box-shadow: 0 4px 12px rgba(16, 40, 58, .22);
}
.kd-top-btn:hover { background: #0369A1; }
.kd-top-btn:focus-visible {
  outline: 3px solid #10283A;
  outline-offset: 3px;
}

2. スクロールしたら出てくる

ページの先頭にいるときはボタンを隠し、少し下へ読み進めたら、ふわっと出す形です。どこまで来たかは短いJavaScriptで見て、is-show という目印のクラスを付けたり外したりします。隠している間は visibility: hidden にして、見えないボタンにキーボードで止まらないようにしています。

HTML
<a class="kd-top-fade" href="#top" aria-label="ページの先頭へ戻る">
  <svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true">
    <path d="M6 15l6-6 6 6" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/>
  </svg>
</a>
CSS
.kd-top-fade {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 100;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  color: #FFFFFF;
  background: #0284C7;
  box-shadow: 0 4px 12px rgba(16, 40, 58, .22);
  /* 最初は隠しておく */
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity .3s, transform .3s, visibility .3s;
}
/* JavaScriptで is-show が付いたら出す */
.kd-top-fade.is-show {
  opacity: 1;
  visibility: visible;
  transform: none;
}
.kd-top-fade:focus-visible {
  outline: 3px solid #10283A;
  outline-offset: 3px;
}
@media (prefers-reduced-motion: reduce) {
  .kd-top-fade { transition: none; }
}
JavaScript(</body> の前に)
// 400px より下までスクロールしたら、ボタンを出す
const fadeBtn = document.querySelector('.kd-top-fade');
window.addEventListener('scroll', () => {
  fadeBtn.classList.toggle('is-show', window.scrollY > 400);
}, { passive: true });

3. 読んだ量が分かる輪っか

ボタンのまわりの輪っかが、読み進めた量に合わせて青くなっていく形です。輪っかは conic-gradient(円の中心から、時計の針のように色を塗り分ける指定)で描き、どこまで塗るかを --p という自分で決めた変数で受け取ります。変数の値は短いJavaScriptで入れています。

HTML
<a class="kd-top-ring" href="#top" aria-label="ページの先頭へ戻る">
  <span class="kd-top-ring-in">
    <svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true">
      <path d="M6 15l6-6 6 6" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/>
    </svg>
  </span>
</a>
CSS
.kd-top-ring {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 100;
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  /* --p の割合まで青く塗る(0%〜100%) */
  background: conic-gradient(#0284C7 var(--p, 0%), #D8E6F0 0);
  box-shadow: 0 4px 12px rgba(16, 40, 58, .18);
}
.kd-top-ring-in {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  color: #0284C7;
  background: #FFFFFF;
}
.kd-top-ring:focus-visible {
  outline: 3px solid #10283A;
  outline-offset: 3px;
}
JavaScript(</body> の前に)
// 読み進めた割合を、輪っかの --p に入れる
const ring = document.querySelector('.kd-top-ring');
window.addEventListener('scroll', () => {
  const max = document.documentElement.scrollHeight - window.innerHeight;
  const p = max > 0 ? window.scrollY / max * 100 : 0;
  ring.style.setProperty('--p', p.toFixed(1) + '%');
}, { passive: true });

4. ページの終わりに置く文字のリンク

画面に固定せず、ページのいちばん下に「ページの先頭へ」という文字のリンクを置く形です。画面のどこもふさがず、ほかの固定のボタン(チャットや予約のボタンなど)とも重なりません。文字があるので、何のリンクかが見て分かります。

HTML
<!-- 本文のいちばん下に置く -->
<div class="kd-top-end">
  <a class="kd-top-end-link" href="#top">
    <svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true">
      <path d="M6 15l6-6 6 6" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/>
    </svg>
    ページの先頭へ
  </a>
</div>
CSS
.kd-top-end {
  display: flex;
  justify-content: center;
  padding: 16px 0;
  border-top: 1px solid #D8E6F0;
}
.kd-top-end-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  /* 指で押しやすい高さにする */
  min-height: 44px;
  padding: 0 18px;
  border: 2px solid #0284C7;
  border-radius: 999px;
  color: #0284C7;
  font-size: 14px;
  font-weight: 700;
  text-decoration: none;
}
.kd-top-end-link:hover { background: #E0F2FE; }

仕組み:リンク1つで、ページの先頭へ

1. 行き先を「#top」にしたリンク

リンクの行き先(href)に # から始まる名前を書くと、同じページの中の、その名前(id)を持つ場所へ移動します。目次から見出しへ飛ぶリンクと同じ仕組みです。

その中で #top は特別で、ページの中に id="top" の場所がなくても、ページの先頭へのリンクになります。MDNでは、href="#top" か href="#" で現在のページの先頭へのリンクになり、HTMLの仕様で決まっていると説明されています。そのため、基本の形はJavaScriptを使わずに動きます。

2. scroll-behavior: smooth で、なめらかに

何も指定しないと、リンクを押した瞬間にぱっと先頭が表示されます。html に scroll-behavior: smooth(スクロールの仕方を、なめらかにする指定)を書くと、上へ流れるように戻ります。どこからどこへ戻ったかが目で追えるので、読んでいた人が迷いにくくなります。

MDNによると、この指定は html(ページのいちばん外側の要素)に書くと画面全体に効きます。body に書いても、画面全体には効きません。また、ブラウザがこの指定を無視することも認められています。なめらかに動かなくても、先頭へ戻ること自体は変わりません。

scroll-behavior は、2022年3月から主要なブラウザでそろって使えるようになり、2024年9月からは「Baseline」の広く使える段階になっています。今のブラウザなら、特別な対策なしで使えます。

3. position: fixed で、画面の右下に置いておく

position: fixed(画面に固定する指定)と right・bottom で、ボタンを画面の右下に置きます。ページをスクロールしても、ボタンは同じ場所に残ります。本文の画像などの上に出るように、z-index も付けます。

前回の position: sticky は「途中まで普通に並び、ある位置からくっつく」指定でした。戻るボタンは最初から画面の右下にあってほしいので、fixed を使います。

数値を変えるとどうなるか

ボタンの大きさ(1の見本)

同じボタンで、大きさだけを変えて並べました。

32px:押しにくい
48px:目安の大きさ
64px:本文をふさぐ

32pxは目立ちませんが、指で押すには小さめです。64pxは押しやすい反面、スマホでは本文の右下をはっきりふさぎます。KAKERUでは、48px前後を目安にしています。W3Cのアクセシビリティの基準(WCAG 2.2)では、押す部品は少なくとも24×24ピクセル(またはまわりに十分なすき間)とされているので、それより小さくはしません。

変えるところ小さくすると大きくすると
ボタンの大きさ(width・height)本文をふさがないが、指で押しにくい押しやすいが、スマホでは本文の右下を隠す
右下からの距離(right・bottom)画面の端に寄り、スマホの角の丸みや操作の線に近づく本文の上に食い込み、文字に重なりやすくなる
出てくる位置(2の 400)ページの先頭近くからボタンが出るしばらく読み進めるまでボタンが出ない
動く時間(2の .3s)ぱっと出るゆっくり出るが、長すぎると「出てこない」と感じる

スマホと、見る人への配慮

ボタンには、何をするかを言葉で付ける

矢印だけのボタンは、読み上げソフトでは何のボタンか分かりません。1〜3のコードでは、aria-label="ページの先頭へ戻る"(見えない名前を付ける指定)で、読み上げたときの名前を付けています。矢印の絵(SVG)は aria-hidden="true" で読み上げから外しています。4のように文字があるリンクなら、その文字が名前になります。

キーボードで選んだときに、見えるように

ボタンを <a href="#top"> のリンクで作っているので、キーボードの Tab キーで選び、Enter キーで押せます。選んだときに枠が見えるよう、:focus-visible(キーボードで選んだときだけ当たる指定)で紺色の枠を付けています。2のように隠している間は visibility: hidden にして、見えないボタンに Tab キーで止まらないようにします。opacity: 0(透明にする指定)だけだと、見えないのに選べるボタンが残ります。

動きが苦手な人には、すぐ移動

画面がすーっと動くのが苦手な人もいます。iPhoneの「視差効果を減らす」など、端末の「動きを減らす」設定がオンのときは、prefers-reduced-motion で受け取って、なめらかなスクロールとボタンの出方の動きを止めます。1と2のコードには、この指定を入れています。

ほかの固定ボタンと重ならないように

右下は、チャットのボタンや、予約・電話のボタン、クッキーのお知らせなどが置かれやすい場所です。戻るボタンを足す前に、スマホで右下に何があるかを確かめます。重なる場合は、bottom の値でずらすか、4の「ページの終わりのリンク」にします。

やりすぎ注意

ボタンを跳ねさせたり、ずっと点滅させたりすると、本文を読む目がそちらに引っぱられます。戻るボタンは、必要なときに見つかれば十分な部品です。色はサイトの色に合わせ、動きは出てくるときの一度だけにします。

トミー

戻るボタンは「目立たせる部品」ではなく「探したときにある部品」だと考えています。
右下に置くなら、本文の邪魔をしない大きさと動きに抑えます。

AIに頼むなら

戻るボタンは、Claudeなどの生成AIに頼んでもすぐ作ってもらえます。そのときは「リンクで作る」「大きさと位置」「出し方」「動きを減らす設定」まで、まとめて伝えると手直しが少なく済みます。

ページの先頭に戻るボタンを、HTMLとCSSと短いJavaScriptで作って。
<a href="#top"> のリンクで作り、aria-label を付ける。右下16px、48pxの丸いボタン。
400pxスクロールしたら出す。隠している間は visibility: hidden。prefers-reduced-motion のときは動きを止めて。

AIが出したコードは、そのまま使う前に、次の3つを確かめます。

  • button と JavaScript だけで作られていないか。window.scrollTo を呼ぶ <button> で作ってくることがあります。動きはしますが、JavaScriptが止まると戻れません。基本の形はリンクで足ります
  • キーボードで選べて、名前が読み上げられるか。Tab キーでボタンまで進み、枠が見えるか、Enter で戻れるかを試します。矢印だけのボタンに aria-label が付いているかも見ます
  • スマホで、右下のほかの部品と重ならないか。チャットや予約のボタン、クッキーのお知らせと重なっていないかを、実際のスマホの幅で確かめます

KAKERUならこう使う/使わない

最後に、作り手としての判断です。

使う場面

  • スマホで3〜4画面より長いページ。記事、サービス紹介、よくある質問のように、下まで読んだあとにメニューへ戻りたくなるページには、右下にボタンを置きます
  • 先頭ではじゃまになるページ。ページを開いた直後は、まだ戻る先がありません。2の見本のように、少し読み進めてから出す形にします
  • 長い記事やマニュアル。「あとどれくらいか」が分かると読み進めやすいので、3の輪っか付きを使うことがあります。ただし輪っかは飾りなので、なくても困らない場所に限ります

使わない場面

  • 1〜2画面で終わる短いページ。指で少し戻せば済むので、固定のボタンは置きません。置くなら4のように、ページの終わりに文字のリンクを置きます
  • 右下にチャットや予約のボタンがあるページ。2つのボタンが並ぶと、押したいほうを押し間違えます。そのページで一番押してほしいボタンを優先し、戻るボタンは4の形にします
  • ヘッダーを上に固定しているページ。前回のようにメニューが画面の上に残っているなら、先頭へ戻る必要が少なくなります。両方を置くかは、スマホで画面がどれだけふさがるかを見て決めます
トミー

「よくあるから付ける」ではなく、「下まで読んだ人が、次にどこへ行きたいか」から考えます。
答えが「先頭のメニュー」なら置き、「お問い合わせ」なら、ページの終わりにそのボタンを置くほうが先です。

まとめ

  • トップへ戻るボタンの基本は、href="#top" のリンク1つ。ページに id=”top” がなくても、先頭へのリンクになる
  • html に scroll-behavior: smooth を書くと、なめらかに戻る。body に書いても画面全体には効かない
  • position: fixed で右下に置き、z-index で本文より手前に出す
  • 少し読み進めてから出すなら、短いJavaScriptでクラスを付け外しする。隠している間は visibility: hidden
  • 矢印だけのボタンには aria-label で名前を付け、キーボードで選んだときの枠を見えるようにする
  • 大きさは48px前後が目安。短いページや、右下にほかのボタンがあるページでは、ページの終わりの文字のリンクにする

まずは1の「右下の丸いボタン」のコードをコピーして、長いページで下までスクロールし、押してみてください。そのあと Tab キーでもボタンまで進めるかを試すと、キーボードで使う人の見え方も確かめられます。

参考にした資料

いずれも2026年10月23日に確認しました。ブラウザの対応状況は変わることがあります。最新の情報は各ページでご確認ください。

ふだんの制作の話や、作ったものの裏側は Instagram と X でも出しています。

関連記事

ヘッダーを上に固定するCSS。position: stickyが止まらない原因と、使う・使わないの判断
スクロールでふわっと表示するCSSの動き。コピペで5種類と、使う・使わないの判断
マウスを乗せると動くボタンをCSSだけで コピペで使える5種類と、スマホ・キーボードへの配慮
ページの一番上に戻るボタン。置く・置かないの判断と、押しやすい大きさ

コメントを残す

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

CAPTCHA