scroll-behavior:smoothは履歴に残る

scroll-behavior:smoothは履歴に残る

CSS だけでスムーススクロールが実装できる scroll-behavior: smooth は簡単でいいのですが、デメリットも多く、一番抵抗のあるのはブラウザの履歴に残ることです。

01スムーススクロール実装方法

ページ内リンクにスムーススクロールを実装するには次の方法があります。

  • CSS による
  • Javascript の scrollIntoView() メソッドによる
  • jQuery の animate() メソッドによる
  • smooth-scroll.js ライブラリによる
  • 自作コードによる

それぞれのメリットデメリットは別記事にあります。

また、上記のうち jQuery を除いた4つの方法のデモサイトがあります。

デモサイトは、はてなブログ時代につくったもので、プロ契約が終了し、現在は広告が入ってしまいます。

02自作コードによるスムーススクロール

現在(2023.8.30)このサイトは自作コードによるスムーススクロールを使っています。そのコードは別記事で公開しています。

このコードは、Github に上げてありますので次の一行を body の閉じタグの前(どこでもいい…)あたりに入れておけば、ページ内リンクがスムーススクロールになります。そうしたくないページ内リンクには除外設定も出来ます。

<script src="https://imuzacom.github.io/js/imzSmoothSctoll.min.js"></script>

よろしければどうぞ。

03scroll-behavior: smoothは履歴に残る

で、このコード、最後にむにゅと着地するような感じがとても気に入っているのですが、ちょっと飽きてきた(笑)ことやできるだけ軽量にしようと思い、CSS の scroll-behavior: smooth を使ってみたところ、

html{
    scroll-behavior: smooth;
}

これ、ブラウザの履歴に残りますね。つまり、ページ内でスムーススクロールを繰り返した後に「戻る」をクリックなりマウスジェスチャーしますとページ内リンクをすべて再現します。

これが便利な場合もあるのかも知れませんがかなり鬱陶しいです。

04Javascript の scrollIntoView()

CSS の scroll-behavior を試そうと思ったわけはもう一つあり、それは Google AdSense を入れていますので、ページを開いてすぐにページ内リンクをクリックしますと、正しい目的位置にいかなかったりします。これを解消する方法はないものかと scroll-behavior: smooth を試してみたということです。

でも、だめでした。どの方法をとっても同じですね。結局、CSS でもブラウザが目的位置の Y軸の位置を計算しているということでしょう(調べてはいません…)。

で、結局、まだいろいろ考え中ではあるのですが、履歴を残さず軽量にということで Javascript の scrollIntoView() を使っています。下記サイトの話です。

この場合は、

window.addEventListener('DOMContentLoaded', () => {
	const anchors = document.querySelectorAll('a[href^="#"]');
	Array.prototype.forEach.call(anchors, (anchor) => {
		anchor.addEventListener( 'click', (e) => {
			e.preventDefault();
			const targetElem = document.querySelector(anchor.hash);
			if (targetElem !== null){
				targetElem.scrollIntoView({behavior: 'smooth'});
			}else{
				return;
			}
		});
	});
});

これですべてのページ内リンクがスムーススクロールになります。除外したい場合は、アンカー要素に data-ignore などカスタムデータ属性を追加して dataset を使ってカスタムデータが存在するかどうかをチェックすればいいです。自作コードの記事を参考にしてください。

05hash プロパティは URLデコードされない

上のコードでは、URLフラグメント(ページ内リンクの移動先 # の後の文字列)を取り出すのに hash プロパティを使っています。

この hash プロパティは URLデコードしません。ですので、URLフラグメントに日本語を使っていますと上のコードでは動きません。要素の id にわざわざ日本語を使うケースは少ないかと思いますが、上にも触れましたが、WordPress に移行する前は長くはてなブログを使っており、はてなブログの目次は見出しの文字列そのものを要素の id にする仕様なんです。ですので当然目次の URLフラグメントも日本語になり、hash プロバティで URLフラグメントを取り出そうとしますとエラーになります。

getAttribute(‘href’) で取り出すか、hash プロパティで取り出したものを decodeURI() でデコードするかです。