スムーススクロールをJavaScriptのみで実装してみる
タイトルの通り、スムーススクロールをJavaScriptだけで実装してみました。スムーススクロールというのは、ページ内リンクを押したときになめらかに移動する仕様のことです。
jQueryを使用していませんが、コードもシンプルかつ軽量なのでおすすめです。
はじめに:実装にあたって
以前から目次のリンクをクリックしたとき、見出しに瞬間移動するのがなんとなく味気なく感じていました。そんなときにスムーススクロールの存在を知り、これはいいなぁと。でもjQueryはできれば使いたくない…
そこで、JavaScriptのみでの実装を決意。ついでにヘッダーと見出しがかぶる問題もどうにかしたいなぁと思っていたので、両方を解決するスクリプトを作成しました。いろいろと試行錯誤した結果、満足できる仕上がりになったと思います。
ちなみに、最近オリジナルの自動生成目次も作りました。ブログサービスを問わず使えますので、こちらのほうもぜひチェックしてみてください↓
【全見出しタグ対応】高速&シンプルな自動生成目次 | IB-Note
いろいろな自動生成目次のソースコードを読んで比較検討を重ねた結果、「これだ!」と思う理想の目次を作ることができました。
スクリプトの特徴と使い方
スクリプトの特徴は以下の通りです。
- #が付いたaタグのリンクからIDを取得。
- リンクをクリックしたとき、対象要素になめらかに移動。
- ヘッダー高さ分のオフセットを指定できる。
以下がスクリプトです。</body>
の直前に設置します。
<script>
(function(){
const offset = 70; // ヘッダーの高さ
const links = document.querySelectorAll('a[href^="#"]');
links.forEach((link) => {
link.addEventListener('click', (event) => {
event.preventDefault();
let href = link.getAttribute('href').substr(1);
href = href == '#' ? 'html' : `[id="${href}"]`;
const target = document.querySelector(href);
const rect = target.getBoundingClientRect();
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
const position = rect.top + scrollTop - offset;
window.scrollTo({
top: position,
behavior: 'smooth'
});
});
});
}());
</script>
目次の見出しに#toc-1
のようにIDが付いている場合、上記スクリプトを設置するだけでスムーススクロールの機能が有効になります。
#から始まるリンクのaタグをすべて対象にしているので、例えば<a href="#comments"> ... </a>
のような場合もスムーススクロールの効果が付与され、リンク先までなめらかに移動するようになります。
コード中にコメントを入れていますが、offsetでヘッダーの高さ分のオフセット値を調整できます(デフォルトは70px)。ヘッダーを最上部に固定表示などしていない場合は、0に設定していただければOKです。
コードの解説
以下の部分では、「aタグのうちhrefが#から始まるもの」をすべて取得しています。
const links = document.querySelectorAll('a[href^="#"]');
querySelectorAllと正規表現的な表現を組み合わせることで、jQueryに近い柔軟な指定をすることができるので便利ですね。
要素を取得すると、それぞれの要素(リンク)に対してクリックイベントを登録します。リンクはそのままだとクリックした瞬間に遷移してしまうので、以下のコードでデフォルトの挙動を禁止します(最初ここでハマって2時間ほど費やしました)。
event.preventDefault();
取得したリンク要素をもとに、移動先要素の情報を取得していきます。以下のコードでは、リンク要素のhrefから移動先要素のIDを取得します。
let href = link.getAttribute('href').substr(1);
href = href == '#' ? 'html' : `[id="${href}"]`;
hrefが#のみの場合はページ全体(html)を指定し、それ以外は'[id="XX"]'
となるように指定します。
hrefから移動先要素を取得すると、移動先要素の絶対位置(position)を計算し、以下のコードで望みの位置までなめらかにスクロールします。
window.scrollTo({
top: position,
behavior: 'smooth'
});
コメントを書き込む