css でスムーススクロールを有効にしたときの位置調整とページ内検索には効かないようにする方法

CSS
もち
もち

javascriptを使わずにスムーススクロールを実装できるscroll-behaviorを使った際に、

ページ内検索などにも影響が出るのを防ぐ方法と、ヘッダーなどが被らないようにする方法をお伝えします。

scroll-behavior: smooth; は、ページ内リンクなどを使うときに一瞬で飛ぶのではなく、滑らかに移動しながら目的の位置まで到達するようになる機能なのですが、

ページ内リンク以外の機能にもスムーススクロールが有効になってしまうという、少し困った性能をしています。

重大な欠陥などがあるわけではないので、そこまで気にする必要もないのかもしれませんが、ページ内リンクにのみ有効にできるならそれに越したことはないのかな?とも思ったので、

コリスさんの記事を眺めていた時に発見した、

(多分)リンクにのみ、スムーススクロールを実装する方法をご紹介します。

動作を確認した感じ、少なくともページ内リンクには影響がありませんでした。

(多分)リンクにのみ有効になる方法

実装方法は簡単で、

html:focus-within {scroll-behavior: smooth;}
どっちも同じ(下の方が詳細度が高い)
:root:focus-within {scroll-behavior: smooth;}
// ページ内リンクの対象になる要素にtabindex="-1"をつける
<section id="section" tabindex="-1"></section>

:focus-withinはフォーカスすることができる要素、もしくは要素の子要素にフォーカスできる要素がある場合に有効な擬似クラスで、a button など、もしくは a button などを子要素に持つ要素に有効になります。

他にもtabindex属性をつけた要素にも有効になり、tabindex=”-1″だったとしても有効になるようです。

tabindex=”-1″を要素につけると、フォーカスが効かなくなるのですが、不思議なことにfocus-withinの対象になるようです。

いちいちtabindex=”-1″を指定しなくてはいけないので、それだけは忘れないようにしてください。

スクロール時の位置調整

ページ内リンクを有効にしたときに、ヘッダーが追従する場合、ヘッダーと移動先の要素が被ってしまい、移動先の要素の見出しなどが見えなくなったりすることがよくあるのですが、

以下のように指定すると簡単に解決できます。

html {
  scroll-padding-top: headerと同じ高さ
  scroll-behavior: smooth;
}
/* :rootでも可 */

scroll-padding-top は手動ではなく、自動的にスクロールが行われたときに有効になる機能で、これらをheaderと同じ高さ分指定しておくことで、被ることがなくなります。

headerの高さをcss変数(カスタムプロパティ)で定義しておけば、headerの高さを変える場合でも、css変数の値を変えるだけでscroll-padding-topとheaderの高さの二箇所を同時に変更できるのでおすすめです。(↓)

/* 
  css変数は詳細度の関係からhtmlではなく、:rootがいいらしい
  というか、どのサイト見ても:rootしか使ってなかったです。
*/
:root {
  --header-height: 80px; /* headerの高さを変える時はここだけ変えれば良くなる */
  scroll-padding-top: var(--header-height);
}

header {
  height: var(--header-height);
}

scroll-padding-topの他に似たような役割を持つ、scroll-margin-topがありますが、結構役割が違っていて、

scroll-padding-topはhtmlなどのスクロールすることができる要素につけることで有効になり、

scroll-margin-topはスクロールする要素の中にある子要素(htmlなどの子要素)につけることで有効になります。

<a href="#test1">test1</a>
<a href="#test2">test2</a>

<section id="test1"></section>
<section id="test2"></section>

例えば、↑のようにページ内リンクが複数あるときに、

リンクをクリックしてスクロールさせた時に、

  • どの要素に飛んでもページ上部に隙間を空けたいときは、scroll-padding-top
  • 特定の要素に飛んだ時のみ、ページ上部に隙間を開けたいときは、scroll-margin-topを使う

といった感じで使い分けるといいと思います。

:root {
  scroll-padding-top: 100px; /* どの要素にスクロールしても100pxは空く */
}

/* :root(html)ではなく、section#test1に指定していることに注意! */
#test1 {
  scroll-margin-top: 300px; /* この要素のみスクロールした時に300px空く */
}
もち
もち

今回はここまでになります。

最後まで見てくださりありがとうございました!

この記事がお役に立てばうれしいです!

タイトルとURLをコピーしました