【HTML】自動的に目次が作れるアウトライン

正しく section 要素などセクションを表す要素や、h1 ~ h6 要素hgroup 要素を適切にマークアップすれば、機械的にそのページの目次が作れるはずです。HTML 仕様では、それをアウトラインと呼びますが、そのアルゴリズムが規定されています。

作成中のページで期待通りにアウトラインが作られないのであれば、それはマークアップに不備があるはずです。今回は、適切な文書構造をマークアップできるよう、そのアウトラインが作られる仕組みや、アウトラインを確認する方法について紹介します。

セクションとは

HTML を学んでいる人にセクションとは何かと聞けば、article 要素section 要素aside 要素nav 要素のことだと答える人が多いでしょう。間違いではありませんが、それがすべてではありません。h1 ~ h6 要素hgroup 要素からセクションも作られるのです。具体例を見てみましょう。

<body>
  <hgroup>
    <h1>ページタイトル</h1>
    <h2>サブタイトル</h2>
  </hgroup>
  <p>あいうえお。</p>
  <h2>見出し1</h2>
  <p>かきくけこ。</p>
  <h3>見出し1.1</h3>
  <p>さしすせそ。</p>
  <h3>見出し1.2</h3>
  <p>たちつてと。</p>
  <h2>見出し2</h2>
  <p>なにぬねの。</p>
</body>

このマークアップの場合、セクションは次のように分けられます。

まず body 要素で一つのセクションが作られます。この body 要素のセクションの見出しは、その中で最初に現れた見出し要素、つまり h1 要素の「ページタイトル」です。以降、h2 などの見出し要素が現れるたびに、新たなセクションが作られていきます。

アウトライン形成の流れ

前述のマークアップのアウトラインは次のように形成されます。これが形成される過程をもう少し詳しく見ていきましょう。

ページタイトル
  見出し1
    見出し1.1
    見出し1.2
  見出し2

hgroup 要素の場合、もっともランクが高い見出し要素の内容が、その見出しになります。そのため、「ページタイトル」が見出しになります。次に h2 要素に出くわします。h1 の次に h2 ですから、見出しランクが一つ下がります。さらに HTML を下がっていくと h3 要素に出くわします。h2 から h3 に移ったため、ここでも見出しランクが一つ下がります。

このように、HTML を上から順に走査し、見出し要素に出くわすたびにセクションが新たに作られたとみなします。そして、手前の見出し要素の見出しランクが上がったのか下がったのかに応じて、セクションの階層が上がったり下がったりするのです。

なお、アウトライン形成時に、見出しランクは上がったのか下がったのかのみを見ます。ランクが何段階上がったのか下がったのかは関係ありません。そのため、つぎのマークアップも、前述のマークアップと全く同じアウトラインを形成します。

<body>
  <hgroup>
    <h1>ページタイトル</h1>
    <h2>サブタイトル</h2>
  </hgroup>
  <p>あいうえお。</p>
  <h3>見出し1</h3>
  <p>かきくけこ。</p>
  <h6>見出し1.1</h6>
  <p>さしすせそ。</p>
  <h6>見出し1.2</h6>
  <p>たちつてと。</p>
  <h2>見出し2</h2>
  <p>なにぬねの。</p>
</body>

同じアウトラインが形成されるとはいえ、このようなランクがでたらめな見出し要素を使うのは避けたほうが良いことは言うまでもありません。

section 要素は無くても良い?

前述の通り、section 要素などのセクションを表す要素がなくても、期待通りにアウトラインが作られました。では、アウトライン生成という側面だけから見た場合、section 要素などは不要なのでしょうか?いえ、そんなことはありません。次のマークアップをご覧ください。

<body>
  <h1>商品一覧</h1>
  <div>
    <p>今日だけの特価セール!</p>
    <h2>Apoh iPon 13</h2>
    <p>…</p>
  </div>
  <div>
    <p>残りわずか!</p>
    <h2>SONNY Xepia 5 III</h2>
    <p>…</p>
  </div>
</body>

このマークアップのアウトラインは次の通り期待通りになります。

商品一覧
  Apoh iPon 13
  SONNY Xepia 5 III

ところが、セクションの区切り位置が機械的に読み取れませんね。もし見出し要素に遭遇したときをセクションの開始と仮定すると、おかしな位置でセクションが分離されてしまいます。以下は強引に分離したときのイメージです。

もちろん、もう少しマシな分離アルゴリズムを考えられないわけではないと思いますが、やはりあらゆるマークアップを網羅するようなアルゴリズムを作るのは難しいと言えます。

上記のマークアップのうち div 要素を section 要素に置き換えれば、確実に期待通りの位置にセクションの開始を持ってくることができます。

section 要素を使った場合のアウトライン形成

前述のマークアップのうち div 要素を section 要素に置き換えた場合のアウトライン形成を見てみましょう。

<body>
  <h1>商品一覧</h1>
  <section>
    <p>今日だけの特価セール!</p>
    <h2>Apoh iPon 13</h2>
    <p>…</p>
  </section>
  <section>
    <p>残りわずか!</p>
    <h2>SONNY Xepia 5 III</h2>
    <p>…</p>
  </section>
</body>

まず body 要素の開始タグから順に下がっていき、最初に出くわした見出し要素は h1 要素で内容は「商品一覧」です。ここまでは以前の例と同じです。

商品一覧

次に section 要素の開始タグに出くわします。この時点で新たなアウトラインが作られますが、見出しなしの状態となります。

商品一覧
  見出しなし

さらに下がっていくと h2 要素に出くわします。この時点で先ほど空欄にしてあったアウトラインの見出しが「Apoh iPon 13」で埋まります。

商品一覧
  Apoh iPon 13

さらに下がっていくと、section 要素の終了タグに出くわします。この時点で先ほどのセクションは終了しますが、すぐにまた新たな section 要素の開始タグに出くわします。この時点で見出しなしの状態のアウトラインが作られます。

商品一覧
  Apoh iPon 13
  見出しなし

さらに下がっていくと h2 要素に出くわします。 この時点で先ほど空欄にしてあったアウトラインの見出しが「SONNY Xepia 5 III」で埋まります。

商品一覧
  Apoh iPon 13
  SONNY Xepia 5 III

以上、section 要素でマークアップされた場合のアウトラインの作られ方を見てきましたが、見出し要素のレベルが一切考慮されなかった点に注目してください。アウトラインが作られるときは、section 要素の開始タグがきっかけであって、見出し要素でありません。そのため、section 要素で適切に文書構造がマークアップされていれば、見出し要素のランクは何でも構わないということになります。次のマークアップも、まったく同じアウトラインを形作ります。

<body>
  <h6>商品一覧</h6>
  <section>
    <p>今日だけの特価セール!</p>
    <h1>Apoh iPon 13</h1>
    <p>…</p>
  </section>
  <section>
    <p>残りわずか!</p>
    <h3>SONNY Xepia 5 III</h3>
    <p>…</p>
  </section>
</body>

もちろん、このような混乱を招くマークアップをするべきでないことは言うまでもありません。しかし、アウトラインの作られ方の特徴は理解しできたのではないでしょうか。

アウトラインから除外される要素

実は、アウトラインから除外されてしまう要素がいくつか存在します。その要素とは次の通りです。

  • blockquote
  • body
  • details
  • dialog
  • fieldset
  • figure
  • td

これらの要素のことをセクショニングルートと呼びます。名前の通り、セクションの根っこですから、アウトラインの大元ということになります。その視点であれば、body 要素が含まれているのは理解できます。

では、そのほかの要素はどういう役割を持っているのでしょうか。セクショニングルートに親要素が存在する場合、親から見て、そのセクショニングルートのコンテンツはアウトラインから除外されることになります。つまり、これらの要素の中に section 要素や h1 要素があったとしても、親からはアウトラインに現れない、ということになります。

blockquote 要素は、それが一番分かりやすいのではないでしょうか。blockquote 要素は引用です。引用の中に見出しがあったとしても、それは親のページの見出しのはずはありませんから、アウトラインから除外されるのは当然です。

気を付けたいのは td 要素ですね。以前より table 要素でレイアウトを作ってはいけないと言われてきましたが、もし table 要素でレイアウトを作り、td 要素の中にコンテンツをマークアップしたとしたら、アウトライン上は空っぽのページなってしまいます。HTML4 時代のウェブページを現代のアウトラインという視点で眺めたら、面白いかもしれませんね。

アウトラインの確認方法

アウトラインは機械的に判定可能なわけですから、当然、ツールもあります。HTML5 Outliner は非常にシンプルなオンラインのアウトライン確認サイトです。URL を貼り付けても良いですし、マークアップを貼り付けても構いません。シンプルで使いやすいため、筆者はもっぱらこれを使っています。

名前は同じですが、Chrome の拡張機能もあります。

WordPress の自動目次生成

このブログは WordPress を使っていますが、各記事の冒頭に表示された目次を毎度人力で用意するのは大変です。当ブログでは、この記事を執筆時点では RTOC(Rich Table of Contents)というブラグインを使っており、自動的に目次が生成され記事の冒頭に挿入されます。RTOC に限らず、”Table of Contents” で検索すれば、数多くの WordPress プラグインが見つかります。

これらのプラグインが HTML 仕様のアウトライン生成アルゴリズムに基づいているのかは分かりませんが、とても分かりやすいアウトライン生成アルゴリズムの利用シーンなのではないでしょうか。

なお、WordPress では記事中のセクションは section 要素でマークアップされるわけではありません。そのため、前述の目次自動生成プラグインは、見出し要素の見出しランクを見て目次を自動生成しています。適切な見出し要素を選択しないといけませんね。

まとめ

アウトラインがどのように作られるのかを知っていれば、 article 要素section 要素aside 要素nav 要素といったセクションを作り出す要素、そして、h1 ~ h6 要素hgroup 要素といった見出しを作り出す要素を、適切に使いこなせるのではないでしょうか。

ただし、あまりアウトラインにこだわりすぎる必要はありません。前述の HTML5 Outliner でアウトラインを見ると、見苦しい箇所は必ず出てくるでしょう。このブログも理想的なアウトラインどころか、かなりヘンテコなアウトラインが作られています。そんなブログの運営者である筆者が言っても説得力はありませんが、階層の上下関係がおかしくない程度であれば良いのではないでしょうか。

今回は以上で終わりです。最後まで読んでくださりありがとうございました。それでは次回の記事までごきげんよう。

Share