今回はこのサイドバーに目次を追加していきます。
完成イメージ
機能的には、
- クリックしたらリンクしてその項目に飛ぶ
- スクロールしてもついてきてくれる
- 必要ない時には隠れる
ぐらいが欲しい。
デザインは、既にあるサイドバーの項目(プロフィール)のものを踏襲する形にします。
記事ページの目次
では、 h タグから自動的に目次を生成してくれる機能が備わっているので、とりあえずそれを利用してみます。
sidebar.html1<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;
とすれば、スクロールしても動かなくなります。
その後、top
やleft
で位置を調整します。
custom.scss1.sidebar-toc {2position: fixed;3top: 0;4}
しかし、これではスクロール量が少ないときに、ヘッダやサイドバーの他の項目と重なってしまいます。
必要ない時には隠れる
スクロール量を取得して、一定の値より小さければ非表示にします。
custom.js1// sidebar-toc というクラス名の要素のリストを取得し、その最初の要素を取得2var toc = document.getElementsByClassName('sidebar-toc')[0];34if (toc) {5// スクロールが起きたときに関数を実行6window.addEventListener('scroll', function () {7// スクロール量が一定値より大きいとき8// sidebar-toc のクラスに show を追加9window.scrollY > 1000 ? toc.classList.add('show') : toc.classList.remove('show');10});11}
クラスを追加することによって、これを CSS で表示・非表示を切り替えることができるようになりました。
custom.scss1.sidebar-toc {2position: fixed;3top: 0;4opacity: 0; // 透過度を0にして非表示5pointer-events: none; // リンクを無効に6transition: opacity 0.5s ease-in-out;7&.show {8opacity: 1; // 透過度を1にして表示9pointer-events: auto; // リンクを有効に10}11}
display: none;
だとアニメーションできず瞬間で消えたり現れたりするので、
フェードイン・フェードアウトするようにopacity
を使っています。
pointer-events
は、マウスポインタをあてたときに反応する領域を指定するもので、
none
に設定することでリンクを無効にできます。
以上で記事ページに目次を設置することができました。
しかし、これと同じ方法では.TableOfContents
が使えない場合に目次を設置することはできません。
長くなってしまったので、そのへんのお話はこちらをどうぞ。
最後まで読んでくださってありがとうございました