ウェブ系Nuxtブログ

Nuxt+Contentfulでmarkdown-itを使ったブログで目次を作る方法

Nuxt.jsならJavascriptだけでブログが作れて簡単なのですが、Wordpressならプラグインで導入できるようなことでも自分で実装しなければいけないことがあり少々面倒ですね...!

今回は、記事の内容から自動で目次を生成する設定を紹介します。
markdown-itの追加プラグインで実装しています。
設定すると、↓のような目次を自動で生成することができます。

使用するプラグインのインストール

今回追加するプラグインをインストールします。
markdown-it-anchor - npm : ヘッダー(h2など)までスクロールするアンカーリンクを作成する
markdown-it-table-of-contents - npm : 記事のヘッダー要素から目次を作成する

$ npm install markdown-it-anchor markdown-it-table-of-contents

インストールしたプラグインをplugins/markdownit.jsの中で読み込みます。
以前の記事で作成したplugins/markdownit.js内に以下の2行を追加します。
もしplugins/markdownit.jsがない場合は作成し、nuxt.comfig.jsのpluginsに~/plugins/markdownit.jsを追加します。

// plugins/markdownit.js
import MarkdownIt from 'markdown-it'

export default ({ app }, inject) => {

    const md = new MarkdownIt({
        html: true,
        linkify: true,
        typography: true,
    })

    md.use(require("markdown-it-anchor"))             // 追加
    md.use(require("markdown-it-table-of-contents"))  // 追加
    
   // 後略
}

ここまでで目次の自動生成ができるようになっています。
Contentfulの記事内で目次を表示したい箇所に[[toc]]と記述することで、次のような目次が生成されます。

contentful-markdown-toc

toc-preview

しかし、これだけでは目次なのか何かのリストなのか分かりにくいので、デザインを変更していきます。

目次のデザインを変更

markdown-it-table-of-contentsのプラグインで生成された目次は<div class="table-of-contents"></div>で囲まれます。
なので、このクラスのスタイルを変更していきます。
今回は以下のように設定してみます。

_slug.vue

/* scss */
    .post-content {
      padding: 0 0 15px;
      position: relative;
      z-index: 1;
      > * {
        position: relative;
        z-index: 10; // h2のpadding部分より前面に来るように
      }
      .table-of-contents {
        background: #f3f3f3;
        border: 1px solid #ccc;
        padding: 5px 10px;
        width: fit-content;
        ul {
          padding-left: 24px;
        }
        &:before {
          content: '目次';
          font-weight: bold;
          font-size: 16px;
        }
      }
    }

すると、↓のように表示できます。
CSSのbeforeセレクタで"目次"の文字を追加しています。

toc-design

目次のリンクをクリックすることで、該当するヘッダー要素までスクロールします。

しかしこのままでは、当ブログのようにブログ上部にメニューなどの固定された要素がある場合、ヘッダー要素が下に潜り込んで隠れてしまいます。 (※2020/1/21追記:現在ヘッダーの固定はスマホ表示のみにしています。)
そこで、marginとpaddingをセットすることで重ならない位置までスクロールさせることが出来ます。

当ブログではh2要素に次のようなスタイルを設定しています。

/* scss */
      h2 {
        font-size: 24px;
        margin-top: -64px;
        padding: 80px 5px 0;
        position: relative;
        z-index: 1;
        &:before {
          content: '';
          height: 34px;
          width: 100%;
          background: #d6d6d6;
          position: absolute;
          top: 80px;
          left: 0;
          z-index: -1;
        }
      }

toc-header-margin

参考にしていただければと思います!

これで、記事内のヘッダーへジャンプできる目次を自動で生成することが出来るようになりました。
あとは、目次を表示したい記事の箇所に[[toc]]を記述するのみです。

nuxtでブログを作成した際に公開したリポジトリに、これまでのmarkdown系の設定を反映したmarkdownブランチを作成しました。
Github - izm51/nuxt-blog-test at markdown

これでブログ作成時のメモが尽きたので、これからは新しいことを記事にしていきます!!
ではまた!


コメント欄 ご意見、ご感想お気軽に!間違いなどあれば、ご指摘お願いいたします!