今どきのスムーズスクロール「ページトップに戻る」

今どきのスムーズスクロール「ページトップに戻る」
Image by Shad0wfall from Pixabay

2022.05.20(更新日:2022.05.26)

画面の下に固定されていて、クリックするとスルスルとページ上部に戻るヤツとかページ内リンクとか。
このスルスルとページの上下移動はJS頼りで・・・なんてやらなくともCSSだけで出来ちゃう。
とても簡単なんで絶対忘れるの受け合い。なんで記事にする。

この記事は1年以上経過しています。内容的に古い場合があります。

「scroll-behavior: smooth」これだけでOK

CSSに以下を加えてみる。

/* ページ内すべて適用したい場合 */
html { scroll-behavior: smooth; }

たったこれだけでスムーズスクロールが可能になる。もちろんページ内リンクも同様だ。
ただし「ie」には反映されない。(もういいよね。さらばie)

よくある「ページトップに戻る」を実装する場合(おまけ)

一般的にブラウザの右下あたりに設置され、ある一定のスクロール値になると表示されるようなやつ。
この場合はJSを使う。出っぱなしでいいならこの節は不要。

今回の例は単純に画像を貼り付けて(scrollup.png)実装する。ページの最後の方にでも書き入れる。
なお「scroll-behavior」を使用するので、ページ最上部にあるタグやセレクタをリンク先に指定する。

/* HTML */
<div id="scrollup" class="first"><a href="header"><img src="images/scrollup.png" alt="上へ"></a></div>

クラスセレクタで「first」を付けているのは初回読み込み時に起こるチラ見防止策。CSSも一応。

/* CSS */
#scrollup {
  position: fixed;
  bottom: 10px;
  right: 10px;
  opacity: 0;
  visibility: hidden;
}
#scrollup.first.hide { display: none; }
#scrollup.veiw { animation: fadeIn .5s linear 0s 1 normal forwards; }
#scrollup.hide { animation: fadeOut .5s linear 0s 1 normal forwards; }
#scrollup a {
  display: block;
  width: clamp( 60px, 8vw, 100px );
}

/* @-webkit-keyframesは省略。必要であれば付加 */
@keyframes fadeIn{
  0% {
    opacity: 0;
    visibility: hidden;
  }
  100%{
    opacity: 1;
    visibility: visible;
  }
}

@keyframes fadeOut{
  0% {
    opacity: 1;
    visibility: visible;
  }
  100%{
    opacity: 0;
    visibility: hidden;
  }
}

まず「position: fixed」で位置を固定。アニメーションはフェードイン・アウトをそれぞれ作成し、設定したスクロール値に入った・抜けた場合のセレクタにそれぞれ指定する。
チラ見を防止するために初回のクラスセレクタ「first」とJSで付加するクラスセレクタ「hide」が付く場合は非表示にしてある。

折角なのでIntersectionObserverを使ってみる

イマイチ朧げなんだが、勉強ついでに使ってみた。
今回はヘッダー部分を監視対象として「scrollup」部分の表示を行ってみる。つまりヘッダー部分が表示されてる場合はクラスセレクタ「hide」を付加し「veiw」を削除して非表示、表示されなくなったら(上にスクロール)クラスセレクタ「veiw」を付加し「hide」削除して表示と言う具合。

/* javascript */
const scrollup = document.querySelector('#scrollup');
const header = document.querySelector('header');
const options = {
  root: null,
  rootMargin: '0px',
  threshold: 0
};
const observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      scrollup.classList.remove('veiw');
      scrollup.classList.add('hide');
    } else {
      scrollup.classList.remove('first');
      scrollup.classList.remove('hide');
      scrollup.classList.add('veiw');
    }
  });
}, options);
observer.observe(header);

まとめ

今まで通りにjQueryあたりでやれば、もっと簡単だなぁーと思う。
また正直もっとスマートに書けるのかもしれない・・・がやりたい事は出来たので良しとする。

うーん・・・JSはまだまだ苦手。