目次に戻るリンクをクリックしたら目次を開く

長い記事を読んでいると、目次に戻りたいなと思うことはありませんか? そんなときに便利なのが「目次に戻る」リンクです。ページの途中でもこれをポチッと押すだけで目次に戻れるので、ページの全体像を把握しながら興味のある項目にすばやくアクセスできます。

ところで目次の中には展開式のものもありますよね。リンクを押したら、目次へ戻るだけでなく目次がパッと展開してくれたらさらに便利だと思いませんか? 必要なときにサッと目次が開いてくれると、探している項目が一発でわかりますし、記事全体がもっと読みやすくなります。

そこで、ページに目次に戻るリンクを設置し、そのリンクをクリックしたら目次を展開させるスクリプトを作成しました。

アイキャッチ
この記事の目次
目次

目次に戻るリンクの導入

この記事で紹介するスクリプトは、detailssummary で作成された目次に対してのみ有効です。それ以外の要素で作成された目次には使用できません。

記事本文のクラス名を .post-body、目次の ID 名を #toc としています。他のクラス名や ID 名が指定されている場合は適宜コードを変更する必要があります。

また、固定ヘッダーがあるページだと目次に戻るリンクをクリックした際に目次の一部がヘッダーに隠れるおそれがあります。その場合以下のような CSS を指定すると、ヘッダー分だけスクロール位置を上にずらすことができます。

:root{
  --header-height: 60px; /* ヘッダーの高さ */
}
html{
  scroll-padding-top: var(--header-height); /* ヘッダー分だけスクロール位置をずらす */
}

目次に戻るリンクは、画面上に固定表示するものと、見出し h2 の前に挿入するものの 2 種類を作成しました。いずれの場合も JavaScript のコードは </body> の直前に、CSS のコードは head 内に追加してください。

画面内に固定表示する場合

ページ上に目次が存在するとき、body 内に目次に戻るリンクが追加されます。

<script>//<![CDATA[
(function (){
  const toc = document.querySelector('#toc');
  if(!toc) return;
  const a = document.createElement('a');
  a.className = 'back-toc-link';
  a.href = '#toc';
  a.innerHTML = '目次';
  a.title = '目次に戻る';
  document.body.appendChild(a);
  a.addEventListener('click', event => {
    event.preventDefault();
    if(!toc.open) toc.open = true;
    location.href = a.href;
  })
}())
//]]></script>

目次に戻るリンクをクリックしたときにまず目次の開閉チェックを行いたいので、preventDefault() でデフォルトのページ内遷移をキャンセルしています。

目次の開閉チェックを行い、目次が閉じているときは detailsopen 属性を true にし、その後 location.href に目次の ID 名 #toc を指定することで、すでに開いた状態の目次に遷移できます。

CSS の例はこちらです。目次に戻るリンクが右下に固定表示されます。

.back-toc-link{
  position: fixed;
  bottom: 5vw;
  right: 5vw;
  display: block;
  line-height: 4em;
  width: 4em;
  height: 4em;
  text-align: center;
  background: #000;
  color: #fff;
  border-radius: 50%;
  font-weight: bold;
  text-decoration: none;
}
.back-toc-link:hover{
  background: #333;
}

このページの右下にも目次に戻るリンクが表示されているので、目次を閉じた状態でクリックしてみてください。遷移したら、ちゃんと目次が展開されているはずです。

見出し h2 の前に挿入する場合

ページ上に目次が存在し、かつ見出し h2 が 2 個以上あるとき、最初以外の h2 の前に目次に戻るリンクが追加されます。

<script>//<![CDATA[
(function (){
  const toc = document.querySelector('#toc');
  const h2 = document.querySelectorAll('.post-body h2:not(:first-of-type)');
  if(!toc || h2.length === 0) return;
  for(let i = 0; i < h2.length; i++){
    const div = document.createElement('div');
    div.className = 'back-toc';
    const a = document.createElement('a');
    a.href = '#toc';
    a.innerHTML = '↑ 目次に戻る';
    div.appendChild(a);
    h2[i].parentNode.insertBefore(div, h2[i]);
    a.addEventListener('click', event => {
      event.preventDefault();
      if(!toc.open) toc.open = true;
      location.href = a.href;
    })
  }
}())
//]]></script>

基本的な仕組みは前項「画面上に固定表示する場合」で説明した通りですが、2 個目以降の h2 の前に div で囲ったアンカーリンクを挿入しなければいけない関係上コードが長くなっています。

見出しの前に目次に戻るリンクを挿入する方法は以下の記事を参考にしました。

CSS の例はこちらです。目次に戻るリンクが見出しの前に右寄せで表示されます。

.back-toc{
  margin-top: 3em;
  text-align: right;
}
.back-toc a{
  text-decoration: none;
}
.back-toc a:hover{
  text-decoration: underline;
}

この段落の下にも目次に戻るリンクが表示されているので、目次を閉じた状態でクリックしてみてください。遷移したら、ちゃんと目次が展開されているはずです。

あとがき

目次に戻るリンクをクリック→目次をクリックして展開、という流れが面倒に感じたので、リンクのクリックだけでページ内遷移と目次の展開の両方をやってくれるスクリプトを作成しました。

だいぶニッチ寄りのカスタマイズだと思いますが、誰かのお役に立てれば幸いです。ここまでお読みいただきありがとうございました!!

編集
ホーム