【Hugo】ブログの記事ページのサイドバーに固定目次を追加

の記事で、ブログにサイドバーを追加しました。

今回はこのサイドバーに目次を追加していきます。


完成イメージ

機能的には、

  • クリックしたらリンクしてその項目に飛ぶ
  • スクロールしてもついてきてくれる
  • 必要ない時には隠れる

ぐらいが欲しい。

デザインは、既にあるサイドバーの項目(プロフィール)のものを踏襲する形にします。

完成イメージ

記事ページの目次

では、 h タグから自動的に目次を生成してくれる機能が備わっているので、

とりあえずそれを利用してみます。

sidebar.html
1
<div class="sidebar">
2
<div class="profile">
3
<h4 class="sidebar-header">プロフィール</h4>
4
...
5
</div>
6
{{- if .IsPage -}}
7
{{ $enableTOC := .Params.toc | default .Site.Params.enableTOC -}}
8
{{- if $enableTOC -}}
9
<div class="sidebar-toc">
10
<h4 class="sidebar-header">目次</h4>
11
{{- .TableOfContents -}}
12
</div>
13
{{- end -}}
14
{{- end -}}
15
</div>

記事以外のページには目次は必要ないということで、

記事ページにのみ表示という意味で6行目。

enableTOC は config.toml やマークダウンファイルの

で指定されるもので、

目次を表示するかしないかの設定です。

11行目が Hugo の目次を呼び出しています。

これで一応サイドバーに目次を設置することはできました。

「クリックしたらリンクしてその項目に飛ぶ」も最初からついています。

ちなみに Hugo の作った目次の構造は…

ちなみに Hugo の作った目次の構造は次のようになっています。

1
<nav id="TableOfContents">
2
<ul>
3
<li>
4
<a href="#見出し1">見出し1</a>
5
<ul>
6
<li>
7
<a href="#見出し2">見出し2</a>
8
</li>
9
<li>
10
<a href="#見出し3">見出し3</a>
11
</li>
12
</ul>
13
</li>
14
<li>
15
<a href="#見出し4">見出し4</a>
16
</li>
17
</ul>
18
</nav>

このとき目次欄には

  • 見出し1
    • 見出し2
    • 見出し3
  • 見出し4

のように表示されます。


あとの2つの要件「スクロールしてもついてきてくれる」「必要ない時には隠れる」は

CSS と JavaScript で対処します。

スクロールしてもついてきてくれる

CSS でposition: fixed;とすれば、スクロールしても動かなくなります。

その後、topleftで位置を調整します。

custom.scss
1
.sidebar-toc {
2
position: fixed;
3
top: 0;
4
}

しかし、これではスクロール量が少ないときに、ヘッダやサイドバーの他の項目と重なってしまいます。

必要ない時には隠れる

スクロール量を取得して、一定の値より小さければ非表示にします。

custom.js
1
// sidebar-toc というクラス名の要素のリストを取得し、その最初の要素を取得
2
var toc = document.getElementsByClassName('sidebar-toc')[0];
3
 
4
if (toc) {
5
// スクロールが起きたときに関数を実行
6
window.addEventListener('scroll', function () {
7
// スクロール量が一定値より大きいとき
8
// sidebar-toc のクラスに show を追加
9
window.scrollY > 1000 ? toc.classList.add('show') : toc.classList.remove('show');
10
});
11
}

クラスを追加することによって、これを CSS で表示・非表示を切り替えることができるようになりました。

custom.scss
1
.sidebar-toc {
2
position: fixed;
3
top: 0;
4
opacity: 0; // 透過度を0にして非表示
5
pointer-events: none; // リンクを無効に
6
transition: opacity 0.5s ease-in-out;
7
&.show {
8
opacity: 1; // 透過度を1にして表示
9
pointer-events: auto; // リンクを有効に
10
}
11
}

display: none;だとアニメーションできず瞬間で消えたり現れたりするので、

フェードイン・フェードアウトするようにopacityを使っています。

pointer-eventsは、マウスポインタをあてたときに反応する領域を指定するもので、

noneに設定することでリンクを無効にできます。

  関連記事【Hugo】ブログにマウスオーバーでふわっと表示する吹き出しを追加
【Hugo】ブログにマウスオーバーでふわっと表示する吹き出しを追加

以上で記事ページに目次を設置することができました。

しかし、これと同じ方法では.TableOfContentsが使えない場合に目次を設置することはできません。

長くなってしまったので、そのへんのお話はこちらをどうぞ。

  関連記事【Hugo】.TableOfContents が使えないけど目次を追加したいときの対処法
【Hugo】.TableOfContents が使えないけど目次を追加したいときの対処法

最後まで読んでくださってありがとうございました👋