javascriptで半分まで行ったら「上へ戻るボタン」を出現させる方法:備忘録

2024/07/18に公開

下まで行ったら、上に戻りたいな~って思う時、たまにありますよね。
そんな時便利なのがTOPへ戻るボタン的なやつです。
初めて作ってみたのですが意外に簡単だったけど忘れがちなところもあったので、共有します。
余談:ハローメンターというサービスで模写修行の課題をアレンジしたときに加えました

実現したい事


ページの50%、半分まで行ったらこのボタンを出現させる。

スタイルを整える

ここはお好みで調整してください。
矢印は画像です。

<button class="c_scrollToTop js_scrollToTop"></button>
.c_scrollToTop {
   background-color: var(--bg-primary);
   width: 40px;
   height: 40px;
   position: fixed;
   bottom: 10px;
   right: 10px;
   border-radius: 5px;
   display: grid;
   place-items: center;
   z-index: 2;
   opacity: 0;
   transition: 0.3s;
   visibility: hidden;
   &.showButton {
      opacity: 1;
      visibility: visible;
   }
   &::before {
      content: "";
      display: block;
      width: 100%;
      height: 27px;
      background-size: contain;
      background-repeat: no-repeat;
      background-position: center;
      background-image: url(../img/Arrow.svg);
   }
}

jsで50%で出現させる

jsのコードは以下になります。

const scrollToTop = () => {
   const button = document.querySelector(".js_scrollToTop");
   if (!button) {
      return;
   }
   let isActive = false;
   window.addEventListener("scroll", () => {
      const scrollY = window.scrollY;
      const pageHeight = document.documentElement.scrollHeight;
      const viewHeight = document.documentElement.clientHeight;
      const percentage = (scrollY / (pageHeight - viewHeight)) * 100;
      if (percentage > 50 && !isActive) {
         button.classList.add("showButton");
         isActive = true;
      } else if (percentage < 50 && isActive === true) {
         button.classList.remove("showButton");
         isActive = false;
      }
      //elseだけにしてしまうとisActiveの状態の時毎回発動してしまう。そして!isActiveになってまたif文が発動する。isActiveの時一度だけelseを発動させるため、else ifを使う。
   });
   button.addEventListener("click", () => {
      window.scrollTo({ top: 0, behavior: "smooth" });
   });
};
scrollToTop();

まずボタンを取得し、buttonという名前に格納します。
次にボタンがないページでは動作しないようにreturnします。

let isActive = false;

ですが、これはスイッチのようなもので、falseのときtrueにする。trueのときfalseにする。というふうに使います。あとで使います。これがないと、ボタンはすでに表示されてるけど、条件が合致したらまた表示させるコマンドを出してしまいます。二重になるのを防ぐためです。

      const scrollY = window.scrollY; //スクロールした量
      const pageHeight = document.documentElement.scrollHeight; //ページ全体の領域
      const viewHeight = document.documentElement.clientHeight; //可視部分の高さ

上から、
スクロールした量、
ページ全体の領域、
可視部分の高さ。
これでどれだけスクロールしたかの割合を求めます。式は、

const percentage = (scrollY / (pageHeight - viewHeight)) * 100;

です。なぜ引き算が混じるのかというと、例えば、2000pxのページがあったとしても、スクロールできる量(scrollY)は、2000pxではないからです。もし2000pxスクロールできてしまうと、それは画面外にはみ出してしまいます。スクロールできる量は、実際は可視部分を引いたものになります。1600pxとか。
最後に100倍してあげて、パーセンテージに直します。

if (percentage > 50 && !isActive) {
         button.classList.add("showButton");
         isActive = true;
      } else if (percentage < 50 && isActive === true) {
         button.classList.remove("showButton");
         isActive = false;
      }
      //elseだけにしてしまうとisActiveの状態の時毎回発動してしまう。そして!isActiveになってまたif文が発動する。isActiveの時一度だけelseを発動させるため、else ifを使う。
   });

シナリオとして、
25%までスクロールダウンした:何も発生しない

51%までスクロールダウンした:isActiveは最初からfalseなので!isActiveを満たし、かつpercentageが50より上、なのでif文の最初のブロック発動。
cssクラスを付与して、cssアニメーションさせ、ボタンを表示します。
さらにisActiveをtrueにします。

80%までスクロールダウンした:isActiveはtrueなのでif文第一ブロックの!isActiveは満たせず。

30%までスクロールアップした:isActiveはture、さらに50未満なので、第二ブロックが発動します。そしてisActiveをfalseに戻します。

この繰り返し...ということです。

button.addEventListener("click", () => {
      window.scrollTo({ top: 0, behavior: "smooth" });
   });

そして、buttonを押したら上に戻る処理を加えます。

最後に関数を呼び出して終わりです。
以上です、ありがとうございました。
また来週!

Discussion