😺

スムーススクロールについて

に公開

スムーススクロールをCSSのみで実装する方法を考えてみました。
ここ最近JSライブラリなどを使わずに独自で実装しているサイトが多いような気がしており、気になって調べてみました。

今回はscroll-behaviorを使って実装していこうと思いますが、調べていると考慮しなければいけないなと思う点が3つありました。

  • ページない検索でもアニメーションしてしまう
  • リンク先にtabindex属性をつける必要がある
  • PCの設定で「視差効果を減らす」に設定していても動いてしまう

この3つを解決して実装していきたいと思います。

ページない検索でもアニメーションしてしまう

scroll-behavior: smooth; をルート要素(html要素)に指定してしまうと、ページ内検索でもスムーススクロールになってしまいます。これは嫌ですよね。
これは:focus-withinを使えば解決します。
この擬似クラスは「その要素または子孫要素にフォーカスがある場合」にCSSを適用できる擬似クラスです。
以下コードです。

html:focus-within {
  scroll-behavior: smooth;
}

focus-withinの追加によってフォーカスが当たっている時のみ、スクロールが滑らかになります。
しかし、これでは次の懸念点があります。

リンク先にtabindex属性をつける必要がある

focus-withinの追加のみだとChrome/Firefoxではスムーススクロールになりません。
なぜかというと

  1. クリックした要素にフォーカスが当たる
  2. その後リンク先の要素にフォーカスを当てたい
  3. しかし、リンク先の要素にフォーカスの機能がないので該当のCSSが適用されない
    アンカーリンクの場合は、hタグやsectionタグなどにリンクさせることが多いと思います。
    しかしhタグsectionタグなどでは、標準でフォーカスは当たりません。

なので、それらの要素にtabindex属性を追加しましょう。

<section class="focus-item" tabindex="-1">
    これでフォーカスが当たります。
</section>

ここでtabindex属性の値を負の値にしてください。
理由はtabキーでのフォーカスを不可能にするためです。負の値ならなんでも大丈夫なので好きにしてください。
tabキーでのフォーカスを許可する場合は0以上の値を設定してください。好きにしてください。
無駄なコードは増やしたくない派の人間ですが、これは必要なコードなので良いと思っています。tabindexの追加も嫌な人はjsで独自で実装することをお勧めしたいです。

ちなみにこれアクセシビリティ的にどうなんでしょうか?フォーカスが当たらなかったな問題ないと認識しているのですがわからないですね。一度ガツンとアクセシビリティについて調べないとと思いながら違うことしてます。

PCの設定で「視差効果を減らす」に設定していても動いてしまう

webサイトを閲覧している際に、アニメーションを減らすために「視差効果を減らす」をオンにしている人もいると思います。ここまでの実装だと「視差効果を減らす」をオンにしていても動いてしまうので、これに対応していこうと思います。
prefers-reduced-motionというメディアクエリを使います。これはユーザーの設定に応じて余計な動きを軽減するためのメディアクエリです。
以下コードです。

@media (prefers-reduced-motion: no-preference) { 
    html:focus-within {
      scroll-behavior: smooth;
    }
}

これで問題点全てを解決したスムーススクロールが完成しました。
ただ、秒数などをこだわりたい場合はこの実装では対応できないです。理由としてはscroll-behavior: smooth;はイージングを指定できないからです。
今回の実装はシンプルにスムーススクロールをしたい時の実装方法の一つとしてみていただけると嬉しいです。
focus-within/prefers-reduced-motionは他でも使えると思うので覚えておきます。

Discussion