CSS:scroll-behavior:smooth を使わないわけ

ページ内のリンクをスムーズに移動するには、CSSのみ、jQuery、素の Javascript といろいろ方法があり、とにかく一番簡単なのは一行ですむ CSS による方法ですが、残念ながらイージングが指定できません。



比較用デモサイト

スムーススクロールの動きを比較できるデモサイトをつくってみました。

CSSによるもの、javascript scrollIntoView()によるもの、オリジナル Javascript によるもの、smooth-scroll.jsによるものの4つが比較できます。4種類のナビが下の画像のように右に固定してありますので試してみてください。smooth-scroll.js のイージングは easeOutQuint が指定してあります。


f:id:ausnichts:20210711145847j:plain


CSS によるスムーススクロール

一行ですべてのページ内リンク <a href="#hogehoge"><a> がスムーススクロールに変わります。


html{
    scroll-behavior: smooth;
}



問題点


javascript scrollIntoView()による

上の CSS と同様のことが Javascript の scrollIntoView() メソッドで可能になります。



サンプルとしてページトップに戻るコードを簡潔に書いたものです。

<div></div>
<div id="toTop">ページトップへ</div>
<script>
document.getElementById('toTop').addEventListener('click', () => {
    document.body.scrollIntoView({behavior: 'smooth'});
});
</script>


問題点

CSS とほぼ同じです。


オリジナル Javascript による

このサイトに使っているものです。

考え方は、現在位置から移動先位置までのピクセル値を 1/20 ずつ移動し、その都度現在位置を変更していく方法で、それですといつまでたっても移動先に到達できませんので移動ピクセル値に 1 を足しています。 スクロール時間は移動ピクセル値に依存しますので 1/20 の分母を大きくすればゆっくりになりますし、小さくすれば速くなります。


<div></div>
<div id="toTop">ページトップへ</div>
<script>
const smoothScroll = () => {
    let startY = window.pageYOffset;
    const scroll = () => {
        startY = window.pageYOffset;
        let y = startY - (startY - 0) / 20 - 1;
        window.scrollTo(0, y);
        if (y < 0) return;
        requestAnimationFrame(scroll);
    };
    requestAnimationFrame(scroll);
};
document.getElementById('toTop').addEventListener('click', smoothScroll);
</script>


まずシンプルにページトップへ戻る部分だけ抜き出しています。もう少し汎用性のあるものはこの記事の最後です。スクロールの最後にムニュっと止まるところが気に入って使っています。


smooth-scroll.jsによる

おそらくこれが一番使われているのではないかと思うライブラリです。jQuery は必要ありません。



イージングはもちろんのことオプションも豊富ですのでかなり汎用性は高いと思います。

サンプルは単純にページトップに戻るコードです。


<div></div>
<a data-scroll href="#">ページトップへ</a>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/smooth-scroll/16.1.0/smooth-scroll.min.js"></script>
<script>
    var scroll = new SmoothScroll('a[href*="#"]', {easing: 'easeOutQuint'});
</script>


使用していませんので問題点があるかないかもわかりませんが、スムーススクロールを除外するオプションもありますのでかなり使いやすいのではないかと思います。カスタムイージングも可能なようです。


汎用オリジナル smooth scroll

現時点では、smoothScroll('id名') のように id を指定して呼べば上下どちらへもスムーススクロールするという汎用程度です。トップに戻る場合に id名ではなく数値「0」で指定するなどの改善はできそうです。


window.addEventListener('load', () => {
  const smoothScroll = (target) => {
    const targetY = document.getElementById(target).getBoundingClientRect().top + pageYOffset;
    let startY = window.pageYOffset;
    const f = ( targetY > startY ) ? true : false; // 'down' = true : 'up' = false
    if(f){
        const windowHeight = window.innerHeight;
        const documentHeight = document.body.clientHeight;
        var bottomTop = documentHeight - windowHeight;
    }
    const scroll = () => {
      startY = window.pageYOffset;
      if(f){
        let y = startY + (targetY - startY) / 20 + 1;
        window.scroll(0, y);
        if (y > targetY || y > bottomTop) return;
        requestAnimationFrame(scroll);
      }else{
        let y = startY - (startY - targetY) / 20 - 1;
        window.scrollTo(0, y);
        if (y < targetY) return;
        requestAnimationFrame(scroll);
      }
    };
    requestAnimationFrame(scroll);
  };


ライセンス等

ご使用の場合は以下の注意事項をお守りください。

  • ライセンスは IMUZA.com にあります。
  • 当記事の Javascript を使用してのはてなブログ用テーマの制作、公開は商用以外は自由です。ただし、記事内、あるいは紹介サイト内に IMUZA.com へのリンクを挿入してください。
  • 当記事の CSS への改変、公開は自由です。
  • 特別問題が発生することはありませんが自己責任でお使いください。
    問題が発生した場合は削除すればもとに戻ります。
  • お問い合わせ、バグの報告、仕様変更のご要望等は Contact Us までお願いします。