見出し画像

CSSのスムーススクロールscroll-behavior:smooth時にページ内検索の移動は除外する

CSS でスムーススクロールができる scroll-behavior というプロパティがあります。たった 1 行指定するだけで簡単に実装できてしまうので便利な反面、ユーザビリティの点で問題があります。

ページ内検索の問題

スムーススクロールを指定すると、ページ内検索まで滑らかにスクロールされるようになります。

これではページ内に検索した単語が複数あるとき、目的の情報までたどりつくのに時間がかかってしまいます。

救世主:focus-within

擬似クラス :focus-within は子孫要素の中に :focus 状態の要素があれば適用されます。それを利用して :focus 状態のときにだけスムーススクロールされるようにしています。

<a href="#jump">見出しへ</a>

...

<h2 id="jump" tabindex="-1">...</h2>
html:focus-within {
  scroll-behavior: smooth;
}

しかし、この解決策ではページ内リンクをクリックしたときに Chrome と Firefox でスムーススクロールされなくなってしまいます。

最適解

scroll-behavior: smooth; を指定した 2 つのアニメーションを用意し、:focus されたときにアニメーションを切り替えることでページ検索のときだけスムーススクロールが除外されるようにしています。

<a href="#jump">見出しへ</a>

...

<h2 id="jump">...</h2>
@keyframes smooth-scroll-1 {
  0%, 100% {
    scroll-behavior: smooth;
  }
}
@keyframes smooth-scroll-2 {
  0%, 100% {
    scroll-behavior: smooth;
  }
}
html {
  animation: smooth-scroll-1 1s;
}
html:focus-within {
  animation-name: smooth-scroll-2;
  scroll-behavior: smooth;
}

先ほどの手法と違って tabindex="-1" を指定する必要もなく、CSS だけで完結する解決策なので汎用性も高いです。

@supports not selector(::-internal-media-controls-overlay-cast-button) {
  html {
    scroll-behavior: smooth;
  }
}

また、このテクニックを使うと Safari でスムーススクロールされなくなってしまうため、CSS ハックを使って Chrome 以外のブラウザの場合はそのまま scroll-behavior が適用されるようにしておきます。

この ::-internal-media-controls-overlay-cast-button は非推奨の擬似クラスのため、今後他のブラウザで実装されることはなく安全な CSS ハックです。

デモ


この記事が気に入ったらサポートをしてみませんか?