かすみん日記

暇なときに何か喋ります

【CSS】ページトップボタンの配置:6パターン

ページトップボタンを配置する方法(位置)として、6つのパターンを紹介します。

JavaScriptは使わず、(HTMLと)CSSのみで実装します。

冒頭からクソ長いお気持ち表明を書いてしまったので、結論だけ知りたい人は下のcodepenの埋め込みまでスクロールしてください。

目次

はじめに

最近のWebサイトでは、ページの最上部(トップ)へ戻るためのボタンが、ウインドウ右下に設置されているのをよく見かけます。

その配置にはいくつかの方法が考えられます。

ひとつは、最も単純なもので、コンテンツの最下部やフッターの中に置かれているだけのものです。

しかし、このタイプはページを一番下までスクロールしないとボタンが現れず、ページの途中でトップに戻ろうと思ってもボタンを押せません。

そこで考えられたのが position: fixed;を用いることで、スクロールに関わらずボタンをウインドウ右下に常に固定しておく方法です。

実際この方法でページトップボタンを設置しているサイトがほとんどかと思われますが、少し安直な気がします。

まず、幅の狭いモバイル向けサイトや、コンテンツをウインドウの端まで目一杯広げるLPサイトのようなサイトでない限り、「メインコンテンツの幅=ウインドウの幅」ではないはずです。

実際、LPでない普通のPC向けサイトでは、コンテンツの幅にmax-widthを設定して中央寄せしているサイトが大半かと思います。

このような場合に、メインコンテンツの位置に関わらずウインドウ基準でページトップボタンを設置してしまうと、コンテンツとボタンが離れ過ぎてダサい、あるいはボタンが押しづらいなどと感じるかも知れません。

つまり、言いたいことは、ページトップボタンを固定する位置は「ウインドウの端」ではなく、「コンテンツの端」にすべきということです。

先にも述べたように、これが問題となるのは「コンテンツ幅=ウインドウ幅」であるモバイルサイトやLPサイトではなく、「コンテンツ幅<ウインドウ幅」が顕著になるPC向けサイトにおいてです。

はじめに、ウインドウ基準でボタンを固定するのは「安直」と書きましたが、実際、コンテンツ基準でボタンを固定するためには少し頭を使わなければなりません。

また、モバイルサイトでは仕方がないものの、コンテンツ内にページトップボタンを固定配置すると、コンテンツ要素とボタンが被ってしまって見づらいという問題もあります。

そこでウインドウ幅に余裕があるような場合では、コンテンツ内の右端にボタンを設置するのではなく、コンテンツの「外側」にボタンを配置するのが最もよいのではないかと提案します。

前置きが長くなりましたが、この記事で紹介する6パターンのうち、3つのパターンとは既に出てきた以下の配置場所のことです:

  1. ウインドウ右下にボタンを固定(安直)
  2. コンテンツ内の右下に固定
  3. コンテンツ右下の外側に固定

そして残りの3パターンは上記の配置に、コンテンツの後に来るフッターとページトップボタンが被らないようにするという条件を加えたものです。

これは需要があるのかいまいちわかりませんが、なんとなくその実装方法をググってみると、どの記事でもJavaScriptを用いた方法でしか紹介されていなかったので、私が発明?したCSSのみで実装できる方法を上の3パターンそれぞれに対して紹介しようと思います。

ある程度のHTMLテンプレートは仮定してしまいますが、大体のサイトは同じようなテンプレートに従っているので多分大丈夫かと思います。

それでは早速、ページトップボタン固定のテンプレートを見ていきましょう。

ベースとなるHTML、CSS

以下のような構造のHTMLに、ページトップボタンを挿入したいと思います。

<body>
  <header>
    <div class="wrapper">
      ヘッダー
    </div>
  </header>

  <div class="content">
    <div class="wrapper">
      <main>メイン</main>
      <aside>サイド</aside>
    </div>
  </div>

  <footer>
    <div class="wrapper">
      フッター
    </div>
  </footer>
</body>

CSSは以下の通り。

.wrapper {
  max-width: 500px;
  margin: 0 auto;
}

.content .wrapper {
  display: flex;
}

main {
  min-height: 120vh;
  flex-grow: 1;
}

.wrappermax-widthを設定し、中身を中央寄せしています。

また、.content内の.wrapperdisplay: flex;を設定し、mainasideを横並びにしています。

mainmin-heightはとりあえずページをスクロールできるようにするために書いただけで、flex-grow: 1;は幅いっぱいに広げるための記述です。

このテンプレートに、以下でページトップボタンを挿入していきます。

position: fixed

はじめに完成品のサンプルをまとめて与えておきます。

See the Pen fixed to-pagetop button by nakasu (@nakasu) on CodePen.

上記のサンプルコードを、以下で解説していきます。

1. ウインドウ右下にボタンを固定

最も簡単な、ウインドウ右端にボタンを固定する方法です。

ますは、どこでもいいですが、例えば</footer>の下に以下のコードを追加します。

<div class="to-pagetop">
  <a href="#" class="btn">ページトップへ</a>
</div>

CSSは次のように指定します。

.to-pagetop .btn {
  position: fixed;
  right: 20px;
  bottom: 20px;
}

ページトップボタン.btnを、position: fixed;でウインドウ基準で固定します。

rightbottomで固定する位置を指定します。

rightbottom0にして、marginpaddingで位置を調整しても構いません。

2. コンテンツ内の右下にボタンを固定

.wrapperの中にボタンを入れることで、ウインドウの右端ではなくコンテンツの右端にボタンを固定します。

例えば、</footer>の下に以下のコードを追加します。

<div class="to-pagetop">
  <div class="wrapper">
    <a href="#" class="btn">ページトップへ</a>
  </div>
</div>

CSSは次のように指定します。

.to-pagetop {
  width: 100%;
  position: fixed;
  bottom: 0;
}
.to-pagetop .wrapper {
  position: relative;
}
.to-pagetop .btn {
  position: absolute;
  bottom: 20px;
  right: 20px;
}

まず.to-pagetopウインドウ最下部にfixedします。 このときfixedした要素の幅はautoのように振る舞ってしまうので、改めてwidth: 100%;を指定します。

コンテンツの幅を利用するために.wrapperの中にボタンを入れますが、.wrapperにはposition: relative;を設定しておきます。 そうすることで、ボタンの位置を親要素.wrapperからの相対位置で指定できるようになります。

3. コンテンツ右下の外側にボタンを固定

コンテンツの右端の外側にボタンを固定します。

</footer>の後にボタンを追加します。

<div class="to-pagetop">
  <div class="wrapper"></div>
  <div class="btn-wrapper">
    <a href="#" class="btn">ページトップへ</a>
  </div>
</div>

CSSは次のように指定します。

.to-pagetop {
  display: flex;
  justify-content: center;
}
.to-pagetop .wrapper {
  margin: 0;
  flex-grow: 1;
}
.to-pagetop .btn {
  position: fixed;
  bottom: 20px;
  margin-left: 20px;
}

まずは.to-pagetopflexを設定することで、その子要素である.wrapper.btn-wrapperを横並びで中央寄せします。

.wrapperの中には何も入ってませんが、これは.wrapperに設定された幅(=コンテンツの幅)を利用しているだけです。

また、.wrapperには中央寄せをするために左右のmarginautoに設定していましたが、これが邪魔になってくるのでmargin: 0;でキャンセルします。

この作業が面倒に感じるなら、(.wrapperに設定していた)コンテンツの幅を変数にして覚えておいて、上のHTMLで.wrapperとしているところを適当な要素に変更して、それに覚えておいたコンテンツ幅を設定するだけでもよいです。

あるいは、元からwrapperの中央寄せをmargin: autoではなくて親要素のflexで行っていてもよいです。

また、.wrapperflex-grow: 1;を設定していますが、これはmax-widthで設定した値まで幅を大きくするためのものです。 通常時は自動で最大まで大きくなりますが、親要素をflexとしたときにはflex-grow: 1;を指定しないと幅がその子要素の大きさまで縮んでしまいます。

あとは、.btnposition: fixed;とすればこの体積が0になるので、.wrapperが丁度中央に来るように配置され、そのすぐ右隣に.btn-wrapperが配置されます。

.btn-wrapperには何もスタイルを設定していませんが、これは必要です。 この要素の位置を基準として、ボタンをfixedします。

ボタンの細かな位置は、bottommargin-leftで指定すれば良いでしょう。leftを使ってしまうとbtn-wrapperの外に飛び出してしまうので注意です。

position: sticky

完成品のサンプルまとめです。

See the Pen sticky to-pagetop button by nakasu (@nakasu) on CodePen.

以下でそれぞれの場合について簡単に解説していきます。

1. ウインドウ右下にボタンを配置

ページトップボタンをウインドウ右下に固定するが、フッターとは被らないようにします。

ボタンは.contentの終わりの</div><footer>の間に挿入します。

<div class="to-pagetop">
  <a href="#" class="btn">ページトップへ</a>
</div>

CSSは次のように指定します。

.to-pagetop {
  position: sticky;
  bottom: 0;
}
.to-pagetop .btn {
  position: absolute;
  bottom: 20px;
  right: 20px;
}

まず.to-pagetopをコンテンツの下、フッターの上に配置します。

そしてこのto-pagetopbottom: 0;(フッターの上)を基準にstickyします。

あとはその子要素である.btnabsoluteで相対位置で指定します。

2. コンテンツ内の右下にボタンを配置

.wrapperの中にボタンを入れることで、コンテンツの幅内にボタンを配置します。

ボタンは.contentの終わりの</div><footer>の間に挿入します。

<div class="to-pagetop">
  <div class="wrapper">
    <a href="#" class="btn">ページトップへ</a>
  </div>
</div>

CSSは次のように指定します。

.to-pagetop {
  position: sticky;
  bottom: 0;
}
.to-pagetop.wrapper {
  position: relative;
}
.to-pagetop .btn{
  position: absolute;
  bottom: 20px;
  right: 20px;
}

まず.to-pagetopをフッターの上にstickyして、その中にコンテンツの幅を持つ.wrapperを入れます。

あとは.wrapperposition: relative;を指定することで、.wrapperを基準に.btnを配置することができます。

3. コンテンツ右下の外側にボタンを固定

コンテンツの右端の外側にボタンを固定し、フッターとは被らないようにします。

ボタンは.contentの終わりの</div><footer>の間に挿入します。

<div class="to-pagetop">
  <div class="wrapper"></div>
  <div class="btn-wrapper">
    <a href="#" class="btn">ページトップへ</a>
  </div>
</div>

CSSは次のように指定します。

.to-pagetop {
  position: sticky;
  bottom: 0;
  display: flex;
  justify-content: center;
}
.to-pagetop .wrapper {
  margin: 0;
  flex-grow: 1;
}
.to-pagetop .btn {
  position: absolute;
  bottom: 20px;
  margin-left: 20px;
}

まず.to-pagetopをフッターの上にstickyし、flexで子要素を中央寄せします。

この.wrapperには最初に設定したmarginをキャンセルし、幅が最大となるようにflex-grow: 1;を設定します。

すると.btn-wrapper.wrapperの右端(=コンテンツの右端)に配置されるので、そこからの相対位置で.btnの位置を指定します。

ただし、btnの位置をleftで指定すると.btn-wrapperから飛び出してしまうので、代わりに`margin: left`を使うようにしてください。

おわりに

なんかめっちゃ長くなりました(8000字超)。

あと、これらを実装するのに丸3日ぐらい悩みました。

上の例では、正直よく理解していない挙動も使ってますが、とりあえずはちゃんと動いてるし大丈夫なのかなと思います。

まあこれぐらいはJavaScriptなしで実装しようねという話でした。

ページトップボタンだけでなく、ウインドウ右上によくあるハンバーガーメニューの配置も、上の話と同じようにして実装できるかと思います。

今日はこれくらいにしておきます。お疲れさまでした。

参考

とくになし。