WWW Watch

HTML5 におけるアウトラインに関して簡単解説

HTML5 で重要なアウトラインに関して、なるべくわかりやすく簡単に解説してみます。

HTML5最近、ヨモツネットさんで 「HTML5 でのセクションの誤用にご注意」 なんて記事が出てたり、ちょうど HTML5 Doctor でも 「Document Outlines」 と題してアウトラインの解説記事が上がってたりするので、この 「アウトライン」 について簡単にまとめてみようと思います。解説って言うほど偉そうなものではありませんがなるべくわかりやすく書いてみようかと。

アウトラインを理解することは、HTML5 でマークアップする際にとても重要になりますので覚えておくとよいと思いますよ。

アウトラインとは?

アウトラインとは見出し、フォームタイトル、テーブルタイトル、その他ラベル付けされた要素によって生成される文書構造のこと…なんて書くととても難しそうですが、従来の (X)HTML でも見出し要素のレベルを使い分けることで文書構造を示すというのをやっていたと思います。例えば、

  • 俺の日記(←文書のタイトル)
    • 俺だよ俺(←文書のサブタイトル)
    • 日々の出来事を適当に書いてる日記です。(←文書の概要)
      • ○月○日の出来事(←記事1 のタイトル)
      • 今日はとても暑い日でした。(←記事1 の内容)
      • △月△日の出来事(←記事2 のタイトル)
      • 今日はうどんが美味しい日でした。(←記事2 の内容)
    • 連絡先(←文書のフッタタイトル)
    • 教えないよ(←フッタの内容)

という内容の文書をマークアップする際、HTML 4.01 や XHTML 1.0 なら下記のようにマークアップしますよね (もちろん、これだけが正解というわけではありませんが)。

<body>
 <h1>俺の日記</h1>
 <h2>俺だよ俺</h2>
 <p>日々の出来事を適当に書いてる日記です。</p>
 <h3>○月○日の出来事</h3>
 <p>今日はとても暑い日でした。</p>
 <h3>△月△日の出来事</h3>
 <p>今日はうどんが美味しい日でした。</p>
 <h2>連絡先</h2>
 <p>教えないよ</p>
</body>

文書内で最も大きな見出しに対して h1 要素を使用し、そこから文書内の階層構造に合わせて見出しレベルを変えていくという流れ。記事1 と記事2 はこの文書内では同レベルと考えられるので、同じ h3 要素でマークアップしています。もし記事内で段落分けして小見出しが入るなら、その小見出しには h4 要素以下が使われることになるでしょう。

従来はこのように、見出し要素のレベルを変えることで文書内の構造を示していました。この時、見出しとそれに続くコンテンツ (上の例では p 要素など) によって形成されるブロック (これを 「セクション」 と呼びます) によって示される文書構造を 「アウトライン」 と呼んでいるわけです。

従来の (X)HTML におけるアウトライン生成

従来の (X)HTML で行っていたように、見出しレベルの使い分けによって生成されるアウトラインを 「暗黙的アウトライン」 と呼びます。暗黙的アウトラインの生成は、

  1. 見出しがあったらそれをアウトラインを生成するセクションの始まりとして考える
  2. 次の見出しが出きたら、その見出しのレベルを調べて…
    1. 次の見出しのレベルが現セクションの見出しレベルより下なら、そのセクションは現セクションのサブセクションになる
    2. 同じレベルか上のレベルの見出しなら、現セクションはそこで終わりで、新しいセクションが開始される

というルールで行われます。よって、上で挙げたマークアップ例からアウトラインを示すと下記のようになります。

  1. 俺の日記
    1. 俺だよ俺
      1. ○月○日の出来事
      2. △月△日の出来事
    2. 連絡先

しかし、従来の (X)HTML はここまでが限界で、制作者側で自由にセクションの範囲を明示することができません。これだと文書の内容によって、意図した通りにアウトラインを生成することができないことが多々ありました。※1

HTML5 におけるアウトラインの生成

そこで、HTML5 ではこのセクションの始まりと終わりを明示し、意図したアウトラインを制作者側で生成できる仕組みが付け加えられました。section 要素に代表される 「セクショニング・コンテンツ」 と、いくつかの 「セクショニング・ルート」 となる要素によってアウトラインを 「明示的に」 生成することが可能です。また同時にアウトライン生成のアルゴリズムに関しても仕様として策定されています。

上の説明だとちょっとわかりにくいかもしれませんので例を挙げてみますが、先に挙げたサンプルテキストに対し、下記のようなマークアップをしたとします。

<body>
 <h1>俺の日記</h1>
 <h1>俺だよ俺</h1>
 <p>日々の出来事を適当に書いてる日記です。</p>
 <h1>○月○日の出来事</h1>
 <p>今日はとても暑い日でした。</p>
 <h1>△月△日の出来事</h1>
 <p>今日はうどんが美味しい日でした。</p>
 <h1>連絡先</h1>
 <p>教えないよ</p>
</body>

とっても極端な例ですのであれですが、すべての見出しが同レベルですので、この文書の構造的には、全セクションが同列になり、アウトライン的には下記のようになります。

  1. 俺の日記
  2. 俺だよ俺
  3. ○月○日の出来事
  4. △月△日の出来事
  5. 連絡先

これだと各セクションの階層構造がわからず、正しく文書構造が示せてないですね。ここまで極端なのはないにしても、見出しレベルだけでは意図した通りのアウトラインを生成するのが難しい場合もあります。HTML5 では、このような場合でも各セクションの階層構造を明示することができます。section 要素を使ってそれを示してみると、

<body>
 <h1>俺の日記</h1>
 <section>
  <h1>俺だよ俺</h1>
  <p>日々の出来事を適当に書いてる日記です。</p>
  <section>
   <h1>○月○日の出来事</h1>
   <p>今日はとても暑い日でした。</p>
  </section>
  <section>
   <h1>△月△日の出来事</h1>
   <p>今日はうどんが美味しい日でした。</p>
  </section>
 </section>
 <section>
  <h1>連絡先</h1>
  <p>教えないよ</p>
 </section>
</body>

これによってアウトラインは下記のように示されます。元通り意図した文書構造が示せていると思います。

  1. 俺の日記
    1. 俺だよ俺
      1. ○月○日の出来事
      2. △月△日の出来事
    2. 連絡先

このように HTML5 では見出しレベルに関係なく、セクショニング・コンテンツとなる要素の入れ子によってセクションの範囲や階層構造を明示することができるわけです。

実際、HTML5 の仕様書 (WD) においても下記のように、

Sections may contain headings of any rank, but authors are strongly encouraged to either use only h1 elements, or to use elements of the appropriate rank for the section's nesting level.

Authors are also encouraged to explicitly wrap sections in elements of sectioning content, instead of relying on the implicit sections generated by having multiple headings in one element of sectioning content.

4.4 Sections : HTML5 (W3C Working Draft) から引用

「各セクション内で使える見出しのレベルに制約はないけど、制作者は h1 要素だけを使うか、そのセクションの入れ子レベルに合わせたランクの見出し要素を使うようにしようね」 と書かれています。要するにセクショニング・コンテンツの適切な使用により文書構造さえ正しく示されていれば、見出しは全部 h1 でもいいよというわけです。

また、「見出しによる暗黙的なアウトライン生成に依存せず、セクションを明示してね」 とも書かれていて、見出しのレベルで暗黙的に文書構造が示せる場合でもなるべくセクションを明示することが推奨されています。

セクションを明示する要素とは

HTML5 において、セクションを明示するセクショニング・コンテンツに分類される要素は下記の 4つがあります。

  • article 要素
  • aside 要素
  • nav 要素
  • section 要素

つまり、これら要素でマークアップすると、そのブロックが見出し要素を持つ持たないに関わらず、セクションとして明示され、アウトラインが生成されます。

また、セクショニング・コンテンツとは異なりますが、下記の各要素はセクショニング・ルートとなる要素として、アウトラインを生成します。

  • body 要素
  • blockquote 要素
  • details 要素
  • fieldset 要素
  • figure 要素
  • td 要素

これらセクショニング・ルートとなる要素は、自身はアウトラインを生成しますが、全体のアウトラインには影響を与えないという点がセクショニング・コンテンツと異なる点です。

例えば下記のようなマークアップがあったとして、

<section>
 <h1>○月○日の出来事</h1>
 <blockquote>
  <h2>ここに引用文があります。</h2>
 </blockquote>
</section>
<section>
 <h1>△月△日の出来事</h1>
 <p>テキスト</p>
</section>

アウトラインが下記のようになってしまうんじゃないかと考えるかもしれませんが、

  1. ○月○日の出来事
    1. ここに引用文があります。
  2. △月△日の出来事

実際には下記のように、

  1. ○月○日の出来事
  2. △月△日の出来事

blockquote 要素のアウトラインは全体のアウトラインとは独立したものとして扱われ、影響を与えません。

ところで、前述したマークアップの例では、文書のタイトルとなる h1 要素が body 要素の直下に配置されていますが、body 要素もセクショニング・ルートとしてアウトラインを生成しますので、この h1 要素は body セクションの見出しとして機能することになります。

逆に言えば、下記のように文書全体を section 要素でマークアップしてしまうと、body セクションの見出しがなくなってしまい、その 1レベル下のセクションの見出しとして文書のタイトルが使われてしまいます。結果、アウトラインがおかしいことになります。

<body>
 <section>
  <h1>俺の日記</h1>
  <section>
   <h1>俺だよ俺</h1>
   <p>日々の出来事を適当に書いてる日記です。</p>
   <section>
    <h1>○月○日の出来事</h1>
    <p>今日はとても暑い日でした。</p>
   </section>
   <section>
    <h1>△月△日の出来事</h1>
    <p>今日はうどんが美味しい日でした。</p>
   </section>
  </section>
  <section>
   <h1>連絡先</h1>
   <p>教えないよ</p>
  </section>
 </section>
</body>

見出し要素のないセクションは 「Untitled Section」※2 として扱われますので、上のマークアップのアウトラインは下記のようになってしまいます。

  1. Untitled Section
    1. 俺の日記
      1. 俺だよ俺
        1. ○月○日の出来事
        2. △月△日の出来事
      2. 連絡先

つまり、文書全体の見出しがない状態になってしまうわけですね。ヨモツネットさんで取り上げられていたサイトは、これと同様の間違いをやってしまっていると。

hgroup 要素の扱い

2013年 4月 30日追記
hgroup 要素は HTML5 勧告候補から削除されました。詳しくは 「hgroup 要素が HTML5 勧告候補から削除される」 をご覧ください。

hgroup 要素は HTML5 策定の過程でいまだその存在を議論されている要素ですので将来的にどうなるかは不透明ですが、これを使うことでセクション内に複数ある見出し要素をグループ化し、その中で最もレベルの高い見出し (すべて同レベルの場合は最初に書かれたもの) だけをセクションタイトルとして使用できるようになります。例えば先ほどから挙げているサンプルソースですが、

<body>
 <h1>俺の日記</h1>
 <section>
  <h1>俺だよ俺</h1>
  <p>日々の出来事を適当に書いてる日記です。</p>
  <section>
   <h1>○月○日の出来事</h1>
   <p>今日はとても暑い日でした。</p>
  </section>
…省略…
</body>

タイトルである 「俺の日記」 とサブタイトルの 「俺だよ俺」 の関係に違和感がある人もいるかもしれません。「それって2つ合わせて文書のタイトルなんじゃないの?」 っていう。そんな場合は hgroup 要素の出番です。下記のようにしてみましょう。

<body>
 <hgroup>
  <h1>俺の日記</h1>
  <h1>俺だよ俺</h1>
 </hgroup>
 <p>日々の出来事を適当に書いてる日記です。</p>
 <section>
  <h1>○月○日の出来事</h1>
  <p>今日はとても暑い日でした。</p>
 </section>
…省略…
</body>

するとアウトラインは下記のようになります。

  1. 俺の日記
    1. ○月○日の出来事
    2. △月△日の出来事
    3. 連絡先

ついでに、より文書内の意味に合わせた要素を入れてみると、

<body>
 <header>
  <hgroup>
   <h1>俺の日記</h1>
   <h1>俺だよ俺</h1>
  </hgroup>
  <p>日々の出来事を適当に書いてる日記です。</p>
 </header>
 <article>
  <h1>○月○日の出来事</h1>
  <p>今日はとても暑い日でした。</p>
 </article>
…省略…
</body>

HTML5 っぽくなってきましたね。アウトラインは先ほどと変わりませんよ。

アウトラインを確認するための便利ツール

では実際にアウトラインを確認するとして、どのような方法があるのでしょうか。アウトラインの確認には、いくつかのツールがあります。例えば、Web 上でアウトラインを確認するツールであれば、

があります。HTML ファイルをアップロード、URL を入力、ソースコードをコピペのいずれかをした上で 「Outline this!」 を押せばアウトラインを表示してくれます。

HTML 5 Outliner

サンプルで使っているソースを解析してみると下記のような感じになります。

HTML 5 Outliner

また、主要なブラウザで簡単に使えるブックマークレットとして、

も便利。リンク先のページにはいくつか種類がありますが、Bookmarklet のページから 「outliner.0.5.0.62.html」 をダウンロードして任意のブラウザで開き、「Drag this link to your favorites bar:」 横のリンクをブックマークに登録、アウトラインを確認したいページで実行すれば、アウトラインが表示されます。

HTML5 outliner (h5o)

メンテがかなり前に止まっているので、ブックマークレットのページでは 「Tested in FF3.5 and O10.10」 とか、「Internet Explorer is not supported」 になってしまっていますが、私の環境では、IE9、Firefox 5、Opera 11 で特に問題なく動作しました。ちなみに、h5o は Opera 用の拡張機能版もあります。

あとは、Google Chrome の拡張機能として

というのもあります。当然ながら Google Chrome でしか使えませんが、アドレスバーに表示されるアイコンをワンクリックで今見ているページのアウトラインを表示してくれるので使い勝手はとてもいいですよ。

HTML5 Outliner

まとめ : アウトラインは大事だよ

ということで、HTML5 でのマークアップ時は、アウトラインを常に意識しながら行うとよろしいと思います。

また、今回はわかりやすいように section 要素を中心に使用しましたが、文書内での意味に応じて、同じセクショニング・コンテンツでも article 要素、aside 要素、nav 要素を適切に使い分けましょう。HTML5 は意味づけ的に従来の (X)HTML よりも細かくなっています。「section 要素って div 要素の代わりでしょ?」 みたいな感覚で適当に使うとおかしいことになりますので注意が必要です。

逆に、今までは文書全体を通して h1 ~ h6 をどのように使い分けるかに頭を使っていたと思いますが、HTML5 ではとりあえず各セクションの先頭を h1 要素からはじめれば間違いはないのでその点は楽だと思います。マークアップ時のアプローチの仕方が今までとは少し変わりますね。

しかし解説って難しいですね…

※1
アウトラインを生成、つまり文書構造が明示できないと何か困ることあるの?というのはごもっともなのですが、将来的に検索エンジンのロボットをはじめとしたプログラムが文書を解析する際、文書構造が明示されることで今より正確に内容を把握できるようになり、機械による文書の取り扱いがとっても楽になったり、それによって Web の利便性が向上するかもしれません。すべては未来のために。

※2
セクショニング・コンテンツは必ず見出しを持ち、セクショニング・コンテンツの要素内で最初のヘッディング・コンテンツの要素が見出しとして扱われます。見出しとなる要素がない場合 (つまり名無しの場合) はデフォルト名が使われますが、このデフォルト名をどのように扱うかは仕様としては定められていませんので、文書を扱うプログラムなどによって変わります。ここでは例として 「Untitled Section」 を使っています。

参考リンク

Recent Entry

全ての記事一覧を見る

Hot Entry

逆引きおすすめエントリー