スムーススクロール実装の令和版ベストプラクティス
目次
スムーススクロールとは?
ページ内アンカーリンクなどをクリックまたはタップした際、指定した要素まで滑らかな動きでスクロールさせるテクニックのことを一般的に「スムーススクロール」と呼びます。
WEBサイトでスムーススクロールを実装する場合は、これまでjavascriptを使うケースが多かったと思いますが、IEのサポートが終了した2022年以降からCSSのみでも実装が可能になりました。
scroll-behavior: smooth
CSSプロパティscroll-behavior: smooth
をhtml要素に定義すると、ページのすべてのスクロールが滑らかなスクロールになります。
html要素以外に定義してもスムーススクロールにならないので注意が必要です。
デモを作成したので実際に触ってみるとわかりやすいと思います。
スムーススクロールの実装方法
html要素にscroll-behavior: smooth
を定義するだけです。
CSS
html {
scroll-behavior: smooth;
}
スクロールのターゲットとする要素にid属性を追加し、それに対応するアンカーリンクのhref属性には「# + id名」と設定します。
HTML
<header>
<div id="nav">
<a href="#りんご">りんご</a>
<a href="#ごりら">ごりら</a>
<a href="#らっぱ">らっぱ</a>
</div>
</header>
<main>
<section>
<h2 id="りんご">りんご</h2>
</section>
<section>
<h2 id="ごりら">ごりら</h2>
</section>
<section>
<h2 id="らっぱ">らっぱ</h2>
</section>
</main>
HTMLでは特に変わったことはしなくても良いので、比較的かんたんに実装できるのが嬉しい。
scroll-behavior: smooth
には様々なメリットがあります。
scroll-behaviorのメリット
ランディング時のページ位置が分かりやすい
通常、URLの末尾に#(ハッシュ)を指定すると、ページの読み込み時に対応するid属性の要素までスクロールした状態で表示します。
例えば「https://example.com/article0123#introduction」のように「#introduction」というハッシュがついたリンクからページへ流入すると、ページ内のid="introduction"
の要素のあるスクロール位置で表示します。
scroll-behavior: smooth
を指定することによって、ページ読み込み時にid="introduction"
まで滑らかにスクロールしていくので「今見ているところはページの途中にあるな」ということが視覚的にわかりやすくなります。
※Firefoxではランディング時にはスムーススクロールしません(2023年2月時点)
フォーカス移動時も滑らかになる
scroll-behavior: smooth
なら、キーボードのTabキーなどによるフォーカス移動の際にもスムーススクロールするようになります。
a
タグやbutton
タグ、input
タグなどフォーカス移動ができるHTML要素はあまり多くないので、フォーカス可能な要素同士の距離が離れてしまう場合があります。
フォーカス移動した際にページ内をワープしたように見えてしまい、現在のスクロール位置がわかりにくく混乱してしまいます。
scroll-behavior
を使うことによって、この「ワープした感」を軽減できるのです。
※Firefoxではフォーカス移動時にはスムーススクロールになりません(2023年2月時点)
マウスジェスチャーツールにも対応
Chrome拡張機能などにあるマウスジェスチャー機能によるスクロール動作にも対応できます。
ページトップやページボトムの移動などの操作でも動きが滑らかになります。
※拡張機能によってはスムースにならないものもあるかも知れません
ブラウザの履歴に残る
#(ハッシュ)を利用するので、履歴がブラウザに記録されます。
scroll-behaviorのデメリット
IEに対応していない
今となってはどうでも良い…w
Easingや速度の調整ができない
ブラウザの仕様を利用するため、イージングやスクロール速度の変更はできません。
固定ナビゲーションが被ってしまう対処方法
ブラウザ上部に固定したナビゲーションなど設置しているサイトの場合、スクロールした位置にナビゲーションが重なってしまう事があります。
「ナビが邪魔してテキストが読めない」といった事になるので、固定したナビゲーションの高さ分だけスクロール位置を「ずらす」必要があります。
これまではナビゲーションの高さ分を考慮して、javascriptでスクロール位置を計算していましたが、CSSのみでも対応は可能です。
そこで便利なCSSプロパティがscroll-margin-top
。
:target {
scroll-margin-top: 60px;
}
:target
擬似クラスは、#(ハッシュ)と一致するidを持つ要素です。
scroll-margin-top
を指定した数値の分、スクロールコンテナの座標空間上のマージンを設けることができます。
デモページでも適用しているので、ソースを確認してみてください。
その他の実装方法
javascriptによる実装方法も紹介しておきます。
CSSによる実装のほうがメリットは多いですが、場合によってはJSによる実装も候補に入ると思います。
ケースバイケースで使い分けていくと良いですね。
javascriptで実装
const links = document.querySelectorAll('a[href^="#"]');
for ( let i = 0; i < links.length; i++ ) {
links[i].addEventListener('click', (e) => {
e.preventDefault();
const targetId = e.target.hash;
const targetElement = document.querySelector(decodeURI(targetId));
const elementY = targetElement.getBoundingClientRect().top;
const scrollY = window.pageYOffset;
const offset = 60; // スクロール位置をずらす(px)
window.scrollTo({
top: scrollY + elementY - offset,
behavior: 'smooth'
});
});
}
jQueryで実装
$('a[href^="#"]').on('click', function() {
var speed = 400;
var offset = 60; // スクロール位置をずらす(px)
var $this = $(this);
var href = $this.attr("href");
var target = $(href == "#" || href == "" ? 'html' : href);
var position = target.offset().top - offset
$('body,html').animate({scrollTop:position}, speed, 'swing');
return false
});