【JavaScript】ページトップへ戻るボタンを実装するイマドキの方法

JavaScriptでページトップへ戻るボタンを実装するイマドキの方法

クリックすると、ページトップまで自動でスルスル~っとスクロールしてくれるボタン。標準装備であるかのごとく、大抵のブログには設置してある印象を受けます。もちろん、当ブログでも設置しています。

「ページトップへ戻る」ボタンの実装というのは、ちょっと前までJqueryを使わないと非常に面倒でした。ですが、近年ではCSSやJavaScriptでできることが増え、Jqueryを使わなくても比較的簡単に実装することが可能になってきています。ということで、この記事ではJavaScriptを使った「ページトップへ戻る」ボタンの実装方法についてご紹介してゆこうと思います。

HTML・CSS・JavaScript各種サンプルコードをご用意していますので、コピペするだけでも実装することができます。また、今回ご紹介するのは「ページトップへ戻る」だけでなく、ページ内アンカーにもスクロールできる高機能タイプです。

デモ

当ブログでも同じJavaScriptコードを使っています。

Element.scrollIntoView()

メインとなる処理を軽く説明しておきます。ターゲットの要素までスクロールする処理は、Element.scrollIntoView()メソッドを使います。

Element.scrollIntoView()メソッドは、ターゲットの要素が画面内に収まる位置までスクロールします。画面内に収まる位置というのが一癖ありそうな感じですが、これについては見てもらえれば一目瞭然なので、下のデモで確認してください。

スクロール位置は、startcenterendに加え、nearestも設定できます。nearestは、他3つの中で1番近い位置にスクロールします。これらは、垂直位置(block)だけでなく、水平方向(inline)についても設定が可能です。他に、スクロールを有効にするかどうかの設定があります。

ブラウザの対応状況

Firefox、Chrome、Edge、Operaで対応しています。その他のブラウザはスムーズスクロールに対応していません。スムーズスクロールに対応していないブラウザでも、設定位置への移動は行われます。詳しい対応状況については下記を参照してください。

Can I Use... - scrollIntoView
https://caniuse.com/#search=scrollIntoView

スムーズスクロールについては若干対応状況が厳しめなのですが、ポリフィルがありますので対応させることが可能です。当ブログではポリフィルを導入しています。4KB足らずの小さなスクリプトで、インラインに直で埋め込んでも気にならないコード量です。下記リンクの「Installation and use」の項の、hereがJSファイルのリンクになります。

Smooth Scroll behavior polyfill
https://github.com/iamdustan/smoothscroll

HTML

HTMLのサンプルコードです。「ページトップへ戻る」ボタン専用のクラスtotopを設定しています。後術するCSS・JavaScriptのサンプルコードについても、クラスtotopが設定されているものとします。矢印の表示はafter疑似要素を使っています。

ここを押すとコードをコピーできます。
<div class="totop"></div>

CSS

CSSのサンプルコードです。カーソルが乗ったときに背景色が変わる効果をtransitionで、押したときにひっくり返る効果は、animationを使ってrotateYを変化させることで表現しています。

ここを押すとコードをコピーできます。
.totop {
  position: fixed;
  bottom: 0;
  right: 0;
  line-height: 1;
  text-align: center;
  font-size: 24px;
  width: 48px;
  height: 48px;
  background: blue;
  color: white;
  border-radius: 50%;
  transition: background ease .1s;
  cursor: pointer;
}
.totop:hover {
  background: blueviolet;
}
.totop::after {
  content: "\102C7";
  display: inline-block;
  margin: 12px 0;
}
@-webkit-keyframes frip {
  0% {
    -webkit-transform: rotateY(0deg);
            transform: rotateY(0deg);
  }
  50% {
    -webkit-transform: rotateY(180deg);
            transform: rotateY(180deg);
  }
  100% {
    -webkit-transform: rotateY(0deg);
            transform: rotateY(0deg);
  }
}
@keyframes frip {
  0% {
    -webkit-transform: rotateY(0deg);
            transform: rotateY(0deg);
  }
  50% {
    -webkit-transform: rotateY(180deg);
            transform: rotateY(180deg);
  }
  100% {
    -webkit-transform: rotateY(0deg);
            transform: rotateY(0deg);
  }
}
.frip {
  -webkit-animation: frip ease-out .3s;
          animation: frip ease-out .3s;
}

JavaScript

JavaScriptのサンプルコードです。クラスtotopが設定された要素を取得し、クリックイベントにscrollIntoView()メソッドとCSSアニメーションを設定します。また、ページ内アンカーが設定されたa要素がある場合には、その要素にもscrollIntoView()メソッドを設定します。このスクリプトよりも下にある要素は取得できませんので、body要素の末尾など下の方に配置してください。

ここを押すとコードをコピーできます。
(function(a,b){
  a.addEventListener('click', function() {
    document.body.scrollIntoView({behavior: 'smooth', block: 'start'});
    a.classList.add('frip');
    a.addEventListener('animationend', function(){
      a.classList.remove('frip');
    },false);
  },false);
  b && (function() {
    for(var i = 0, l = b.length; i < l; i++) {
      b[i].addEventListener('click', function(e) {
        e.preventDefault();
        document.getElementById(this.hash.slice(1)).scrollIntoView({behavior: 'smooth', block: 'start'});
      },false);
    }
  })();
})(document.getElementsByClassName('totop')[0],document.querySelectorAll('a[href^="#"]'));

ページをスクロールしたらボタンを表示する

「ある位置までスクロールしたらふわっとボタンが出てくる」というのもよく見かけますので、サンプルコードを載せておきます。

デモ

HTML

ボタンを非表示にするための、クラスvanishを追加しています。

ここを押すとコードをコピーできます。
<div class="totop vanish"></div>

CSS

opacityvisibilityを使ってボタンを表示/非表示にします。transitionでフェードイン・アウトの効果を表現しています。

ここを押すとコードをコピーできます。
.totop {
  opacity: 1;
  visibility: visible;
  position: fixed;
  bottom: 0;
  right: 0;
  line-height: 1;
  text-align: center;
  font-size: 24px;
  width: 48px;
  height: 48px;
  background: blue;
  color: white;
  border-radius: 50%;
  transition: background ease .1s, visibility .3s, opacity ease .3s;
  cursor: pointer;
}
.totop:hover {
  background: blueviolet;
}
.totop::after {
  content: "\102C7";
  display: inline-block;
  margin: 12px 0;
}
.vanish {
  opacity: 0;
  visibility: hidden;
}
@-webkit-keyframes frip {
  0% {
    -webkit-transform: rotateY(0deg);
            transform: rotateY(0deg);
  }
  50% {
    -webkit-transform: rotateY(180deg);
            transform: rotateY(180deg);
  }
  100% {
    -webkit-transform: rotateY(0deg);
            transform: rotateY(0deg);
  }
}
@keyframes frip {
  0% {
    -webkit-transform: rotateY(0deg);
            transform: rotateY(0deg);
  }
  50% {
    -webkit-transform: rotateY(180deg);
            transform: rotateY(180deg);
  }
  100% {
    -webkit-transform: rotateY(0deg);
            transform: rotateY(0deg);
  }
}
.frip {
  -webkit-animation: frip ease-out .3s;
          animation: frip ease-out .3s;
}

JavaScript

スクロールイベントを監視し、クラスvanishを付け外しすることで、表示/非表示を切り替えます。切り替わるラインは、垂直方向500pxに設定しています。

ここを押すとコードをコピーできます。
(function(a,b,c){
  window.onscroll = function() {
    if(window.pageYOffset < 500) {
      c && (function(){
        c = false;
        a.classList.add('vanish');
      })();
    } else {
      c || (function(){
        c = true;
        a.classList.remove('vanish');
      })();
    }
  };
  a.addEventListener('click', function() {
    document.body.scrollIntoView({behavior: 'smooth', block: 'start'});
    a.classList.add('frip');
    a.addEventListener('animationend', function(){
      a.classList.remove('frip');
    },false);
  },false);
  b && (function() {
    for(var i = 0, l = b.length; i < l; i++) {
      b[i].addEventListener('click', function(e) {
        e.preventDefault();
        document.getElementById(this.hash.slice(1)).scrollIntoView({behavior: 'smooth', block: 'start'});
      },false);
    }
  })();
})(document.getElementsByClassName('totop')[0],document.querySelectorAll('a[href^="#"]'),false);

補足

スクロールイベントというのは、スクロール中またはスクロールする度に発生するので、負荷が高くなります。今回はクラスを付けるか外すかの処理だけなので、そこまで大きな負荷はありませんが、念のため少し負荷を抑えるための処理を含めています。

おわりに

「ページトップへ戻る」ボタンを検索すると、Jqueryを使った実装方法がたくさんヒットします。近頃はJqueryを使わないようにしようという動きがあるようですが、Jqueryで実装しても別に良いと思うのです。でも「ページトップへ戻る」ボタンだけのためにJqueryを使うのであれば、この方法をおすすめしたいです。ポリフィルを読み込んだとしても、Jqueryと比べればファイルサイズを大幅に少なくできます。

お知らせ

現在お知らせはありません。

最近の投稿

シェア