HTML5でのコーディング – セクションやらアウトラインやらのコンテンツ・モデル周辺のお話

ここではHTML5で採用されているコンテンツ・モデル周辺のお話をします。具体的にはセクションアウトラインについて、article要素とsection要素の使い分けについて書いていきます。「HTML5ではいくつh1要素を使っても大丈夫」というのを聞いたことのある人は、これを読むとその理由がわかるかもしれません。

HTML5以前とHTML5でのマークアップにおける考え方の違い

HTML5以前のときはWebページを見たときに、この部分がヘッダーでここがフッター、でもってメインイメージがあってレフトコンテンツがあって…みたいにして見た目でパーツに分けていました。そしてそれぞれに対応するようにdiv要素をつくってマークアップしました。<div id="header">だの<div id="left-contents">とかってヤツです。”left-contents”とかって名前をつけるわけですから、HTMLのマークアップの時点ですでにレイアウト(見た目)を意識したものになってます。

これがHTML5では『コンテンツ・モデル』というのになりました。おおざっぱにいうと『レイアウトは全部CSSにまかせてしまってhtmlファイルでは文書構造を明確にしたマークアップをしなさい』ということです。なので、Webページを見たときにどの部分がコンテンツとして独立なのかとか、どこからどこまでが意味のあるまとまりなのかとかそんな感じのことを考えながらマークアップします。極端な例えかもしれませんが、HTML5でのマークアップの仕方を十分習得していると、内容は同じだけどデザインだけが異なる2つのWebページについてまったく同じマークアップができるはずです。HTML5でのマークアップは見た目ではなくて内容に関するマークアップですから。

そしてこのとき重要になってくるのが、HTML5で導入された新要素です。特にセクショニング・コンテンツと呼ばれるarticle、aside、nav、section要素です。これらに関してはセクションやアウトラインといった概念を説明した後に使い分けを見ていきます。

参考ページ

コンテンツ・モデルによる要素の分類

HTML5以前とHTML5では要素の分類が変わりました。これが決定的な違いです。HTML5以前では要素を『インライン要素』と『ブロックレベル要素』に分類していました。インライン要素というのは、要素を並べるとブラウザ上で改行されずに右に配置されていく要素です。a要素やspan要素が代表的です。一方のブロックレベル要素というのは並べると改行されて下に向かって表示されるものです。div要素やp要素がその代表例です。

Webページを作成するときにレイアウトの役割を担うのはCSSです。HTMLではありません。でもHTML5以前ではHTML自体も要素の分類の部分でレイアウトを意識したものになっていました。要素が右に配置されていくか下に配置されていくか、それによって要素を分類していたからです。

HTML5ではこの分類に変わって『コンテンツ・モデル』が採用されました。コンテンツ・モデルではHTMLの要素は7つのカテゴリ

  • メタデータ・コンテンツ
  • フロー・コンテンツ
  • セクショニング・コンテンツ
  • ヘディング・コンテンツ
  • フレージング・コンテンツ
  • エンベッディット・コンテンツ
  • インタラクティブ・コンテンツ

に分類されます。中には複数のカテゴリに属する要素もあります。これによってHTML5ではコンテンツというのを主軸においてコーディングしていくことになります。どの要素がどのカテゴリに分類されているかは参考ページを読んでください。

参考ページ

『セクション』、『アウトライン』という概念

7つのカテゴリに属する要素のうち、使い方を必ず理解しておかないといけないものがセクショニング・コンテンツとヘディング・コンテンツです。それぞれ次のような特徴をもっています;

  • セクショニング・コンテンツ

    見出しやフッターの範囲を定義する。潜在的に見出しとアウトラインをもつ。
    article、aside、nav、section要素がこれに属する。

  • ヘディング・コンテンツ

    セクションのヘッダーを定義する。
    h1、h2、h3、h4、h5、h6要素がヘディング・コンテンツに属する。

セクショニング・コンテンツがセクションという範囲を定義して、セクションのまとまりがアウトラインになります。

…ただこれだけだとイミフなのでコードを書いてアウトラインを見てみます。まずはこのコード

<body>
  <section>
    <h1>hoge</h1>
    <p>hogehogehoge</p>
  </section>
  <article>
  </article>
</body>

をコピーしてHTML 5 Outlinerの「HTML:」の下に貼付けて「Outline this!」をクリックしてください。すると 

  1. Untitled Section
    1. hoge
    2. Untitled Section

というテキストが表示されます。これがアウトラインです。HTML5文書の階層構造のことです。

まずはhogeのところ。ここはセクショニング・コンテンツであるsection要素でh1要素とp要素を囲っています。h1要素の内容は”hoge”です。セクショニング・コンテンツは潜在的に見出しをもつ、ということでした。この潜在的な見出しと、ヘディング・コンテンツに属する要素であるh1が結びついて”hoge”がアウトラインに表示されてます。つまり潜在的な見出しがヘディング・コンテンツによって明示的に宣言されている訳です。そしてp要素で定義される段落がそのセクションの内容になります。”hoge”という見出しと”hogehogehoge”という段落(内容)を含むセクションがsection要素の定義するセクションです。

次に2. Untitled Sectionのところ。ここはセクショニング・コンテンツであるarticle要素がつくるセクションです。でもarticle要素はh1などのヘディング・コンテンツを含みません。なので”Untitled Section”、つまり『見出しをもたないセクション』だと認識されたわけです。またarticle要素の中には先ほどのようなp要素もありません。ですがたとえ空っぽでもセクショニング・コンテンツはセクションを新たに定義します。

ここまでをまとめるとこんな感じです;

<body>
  <section>
<!-- ここから"hoge"という見出しをもったセクションが開始される -->
    <h1>hoge</h1>
    <p>hogehogehoge</p>
<!-- ここで"hoge"という見出しをもったセクションが終了する -->
  </section>
  <article>
<!-- ここから見出しをもたない名無しのセクションが開始される -->
<!-- ここで見出しをもたない名無しセクションが終了する -->
  </article>
</body>

アウトラインを見ると一番上にもUntitled Sectionというのがあります。これは何でしょうか。先ほど『セクションのまとまりがアウトライン』といいました。このアウトラインというのは「何の」アウトラインかというと、セクショニング・ルートのアウトラインなんです。セクショニング・ルートになりうる要素は6つありますが、ここでのセクショニング・ルートはズバリbody要素です。セクショニング・ルート自身はアウトラインの最上位セクションを定義するのでやはり暗黙の見出しをもちます。ですがbody要素の下にはヘディング・コンテンツがありません。なのでアウトラインには”Untitled Section”と表示されたということです。

またsection要素もarticle要素もbody要素内にあります。このとき、sectionやarticleがつくるセクションはbody要素がつくるセクションの子セクションとなります。「ネストされたセクション」ともいいます。ということでまとめるとこんな感じです;

<body>
<!-- ここから見出しをもたない名無しセクションが開始される -->
  <section>
<!-- ここから"hoge"という見出しをもった子セクションが開始される -->
    <h1>hoge</h1>
    <p>hogehogehoge</p>
<!-- ここで"hoge"という見出しをもったセクションが終了する -->
  </section>
  <article>
<!-- ここから見出しをもたない名無しの子セクションが開始される -->
<!-- ここで見出しをもたない名無しセクションが終了する -->
  </article>
<!-- ここで見出しをもたない名無しセクションが終了する -->
</body>

とりあえずHTML5では見出しと内容をもったセクションというのが基本単位になって、そのまとまりがHTML文書のアウトラインと呼ばれる階層構造をつくるということを理解してください。繰り返します。基本単位はセクションで、セクションのまとまりがつくる階層構造がアウトラインです。

参考ページ

ヘディング・コンテンツと暗黙のセクション

次にこんなコードのアウトラインを見てみましょう;

<body>
  <h1>hoge</h1>
  <section>
    <h1>foo</h1>
    <p>foofoofoo</p>
  </section>
  <h2>bar</h2>
</body>

アウトラインはこんな感じになります;

  1. hoge
    1. foo
    2. bar

んっ?ってなりました?sectionもarticleもasideもnavもないのに”bar”が新たなセクションの見出しとして認識されてます。復習を兼ねて一つずつ見ていきましょう。まずはセクショニング・ルートであるbody要素がつくるセクションが始まります。見出しはh1要素になっている”hoge”です。次いでsection要素が新たなセクションを開始します。そのセクションの見出しはh1要素になっている”foo”です。このセクションは”hoge”という見出しのセクションの子セクションになります。そしてsection要素で作られるセクションが終了した後、h2要素になっている”bar”がきます。これが新たなネストされたセクションの見出しになっています。

実はセクション内に2つ以上のヘディング・コンテンツがあると、2つ目以降のヘディング・コンテンツの要素によって暗黙的に新たなセクションが開始されます。そしてその新たなセクションの見出しがそのヘディング・コンテンツになります。今の場合でいうと、body要素にはすでにh1要素である”hoge”があるために、下の”bar”というh2要素によって新たなセクションがつくられ、そのセクションの見出しが”bar”になる、というわけです。

コードで説明するとこんな感じです;

<body>
<!-- ここから"hoge"という見出しをもったセクションが開始される -->
  <h1>hoge</h1>
  <section>
<!-- ここから"foo"という見出しをもった子セクションが開始される -->
    <h1>foo</h1>
    <p>foofoofoo</p>
<!-- ここで"foo"という見出しをもったセクションが終了する -->
  </section>
<!-- ここから"bar"という見出しをもった子セクションが開始される -->
  <h2>bar</h2>
<!-- ここで"bar"という見出しをもったセクションが終了する -->
  </article>
<!-- ここで"hoge"という見出しをもったセクションが終了する -->
</body>

次の例はこれです;

<body>
  <h1>hoge</h1>
  <h2>foo</h2>
  <h3>bar</h3>
</body>

アウトラインはこんな感じになります;

  1. hoge
    1. foo
      1. bar

それほど難しくないと思います。セクショニング・ルートであるbody要素が”hoge”という見出しのセクションをつくって、h2要素によって暗黙的にセクションが開始されてその見出しが”foo”になります。そのセクションはbodyがつくるセクションの子セクションになっています。h3要素によってさらに新たなセクションがつくられて、その見出しは”bar”になります。そしてそれは見出しが”foo”のセクションの子セクション、bodyがつくるセクションの孫セクションとなっています。

最後にもう一つ例を出します;

<body>
  <h1>hoge</h1>
  <section>
    <h2>foo</h2>
    <p>foofoofoo</p>
    <h1>baz</h1>
  </section>
  <h2>bar</h2>
  <h1>quux</h1>
</body>

この場合のアウトラインはこうなります;

  1. hoge
    1. foo
    2. baz
    3. bar
  2. quux

これはちょっとクセがあります。また順番に見ていきましょう。まずはbodyによって最上位のセクションが開始されます。見出しは”hoge”です。次いでsection要素によって子セクションが開始されます。見出しは”foo”、段落は”foofoofood”です。ここまではOKでしょう。

次にh1要素がきています。もしこれがh3、h4、h5、h6であれば、”foo”を見出しにもつセクションの子セクションが開始されます。ところが”foo”の見出しレベルh2に対して”baz”の見出しがh1なので、暗黙に開始されるセクションは子セクションではなく兄弟セクションになります。セクションの見出しと同じかそれよりも高いレベルの見出しがある場合、section要素の中に入っているにも関わらず、section要素がつくるセクションと兄弟関係にある暗黙的セクションが開始される わけです。

section要素を抜けると、h2要素によって”bar”という見出しの暗黙セクションが開始されます。これは直前で閉じられているsection要素によってつくられるセクションと兄弟関係にあります。

最後にh1要素によって”quux”という見出しの暗黙セクションが始まります。これはbody要素の中に入っていますが、body要素の見出しである”hoge”の見出しレベルと同じh1です。ということは先ほど説明したとおり、body要素がつくるセクションと兄弟関係にある暗黙的セクションが暗黙的に開始 されることになります。なので”quux”と”hoge”はアウトライン上では同じ階層のセクションの見出しということになります。

まとめるとこんな感じです;

  • セクショニング・ルートであるbody要素は最上位のセクションをつくる
  • セクションの見出しになるのは、そのセクションをつくる要素内にある最初のヘディング・コンテンツの要素である
  • 二つ目以降のヘディング・コンテンツの要素は暗黙のセクションをつくる
  • 暗黙のセクションをつくる要素の見出しレベルが、その要素が含まれるセクションの見出しレベルと同じかそれ以上のとき、要素が含まれているセクションと兄弟関係にあるセクションが暗黙的につくられる

参考ページ

なぜHTML5はh1要素をいくつも使えるのか

ここまでついてこれたあなた、暗黙的セクションというのがすごく面倒だと思いませんか?そうです、面倒です。なので暗黙セクションを出てこなくさせる方法があります。それはセクションの開始と終了をセクショニング・コンテンツで明示的に宣言することです。さっきの例

<body>
  <h1>hoge</h1>
  <section>
    <h2>foo</h2>
    <p>foofoofoo</p>
    <h1>baz</h1>
  </section>
  <h2>bar</h2>
  <h1>quux</h1>
</body>

であれば

<body>
  <h1>hoge</h1>
  <section>
    <h2>foo</h2>
    <p>foofoofoo</p>
  </section>
  <section>
    <h1>baz</h1>
  </section>
  <section>
    <h2>bar</h2>
  </section>
</body>

と書くことです。下の方は

  1. hoge
    1. foo
    2. baz
    3. bar

というアウトラインになります。注意する点は最後の”quux”部分を削除している点です。”quux”はbody要素がつくるセクションと兄弟関係にあるセクションをつくりました。でもbody要素がつくるセクションと兄弟関係にあるセクションを明示的に宣言する方法は(おそらく)ありません。なのですべて明示的なセクションだけにしたいのなら、bodyがつくる最上位のセクションと兄弟関係にあるようなセクションはつくるべきではありません。

ここですぐ上のコードのh2をh1に変えてみましょう;

<body>
  <h1>hoge</h1>
  <section>
    <h1>foo</h1>
    <p>foofoofoo</p>
  </section>
  <section>
    <h1>baz</h1>
  </section>
  <section>
    <h1>bar</h1>
  </section>
</body>

これはh2をh1に変える前とまったく同じアウトラインになっています。セクショニング・コンテンツの要素を使ってセクション開始の宣言を明示的に行えば、その中のヘディング・コンテンツ要素の見出しレベルが変わっても同じアウトラインをつくるんです。この意味で「HTML5ではいくつh1を使っても大丈夫」なわけです。こう書いた方がコードもずっと分かりやすくなっています。セクショニング・コンテンツで明示的にセクション開始を宣言する限り、その中の見出しはh1で大丈夫なんです。

HTML5以前ではh1要素は一つだけ使うことが望ましいとされていましたが、HTML5だとそれは「body要素の直下におくh1要素は一つだけにするのが望ましい」という意味に変わります。先ほどの例を使うと、

<body>
  <h1>hoge</h1>
  <section>
    <h2>foo</h2>
    <p>foofoofoo</p>
    <h1>baz</h1>
  </section>
  <h2>bar</h2>
  <h1>quux</h1>
</body>

での<h1>quux</h1>のようなものは作らない、ということです。<h1>quux</h1>がつくる暗黙的セクションを明示的に宣言する方法がないからです。

article要素とsection要素の使い分け

最後にセクショニング・コンテンツに属する要素の使い分けを見てみましょう。以下はHTML5.JP – 次世代HTML標準 HTML5情報サイトからの引用です。

  • article 要素 – セクション – HTML要素 – HTML5 タグリファレンス – HTML5.JP

    article要素は、ドキュメント、ページ、アプリケーション、サイトの中の自己完結した構成を表します。つまり、シンジケーションのように、単独で再配布でき再利用できるものです。これはフォーラムの投稿、雑誌や新聞の記事、ブログのエントリ、ユーザーが投稿したコメント、インタラクティブなウィジットやガジェット、その他、コンテンツの独立した項目が考えられます。

  • aside 要素 – セクション – HTML要素 – HTML5 タグリファレンス – HTML5.JP

    aside要素は、その前後のコンテンツには関係しているけれども、やや本筋から逸れながらも軽く触れておきたいようなコンテンツから構成されるページのセクションを表し、コンテンツから分離されたものとして見なすことができます。このようなセクションは、印刷では、よく補足記事として表されるものです。
    この要素は、本文抜粋引用リードや補足記事のような印刷効果、広告、nav 要素のグループ化、ページのメイン・コンテンツから分離しても構わないようなコンテンツに使うことができます。

  • nav 要素 – セクション – HTML要素 – HTML5 タグリファレンス – HTML5.JP

    nav 要素は、他のページやそのページ内の部分へリンクするページのセクション、つまりナビゲーション・リンクを伴うセクションを表します。
    注意:ページ上のすべてのリンクのグループがnav要素の中にある必要はありません。この要素は、主に、主要なナビゲーション・ブロックからなるセクションを対象としています。とりわけ、サービス規約、ホーム、著作権ページといったサイトのさまざまなページへの短いリンク・リストをフッターに入れることが一般的です。このような場合においてはfooter要素だけで十分です。このような場合にもnav要素を使うことができますが、通常は意味がありません。

  • section 要素 – セクション – HTML要素 – HTML5 タグリファレンス – HTML5.JP

    section 要素は、一般的なドキュメント・セクションやアプリケーション・セクションを表します。セクションとは、この文脈においては、コンテンツの主題をグループ化するものです。通常は見出しを伴います。
    セクションの例としては、章や、タブ付きダイアログ・ボックス内の各種ページや、論文の番号付きセクションがあげられるでしょう。ウェブサイトのホームページは、イントロダクション、新着記事、連絡先情報といったセクションに分けられるでしょう。
    注意:section 要素は、汎用的なコンテナ要素ではありません。スタイリング目的やスクリプティングの都合だけで要素が必要になったときは、ウェブ制作者は、代わりに、div 要素を使うことが推奨されます。一般的な規則として、section 要素は、その要素のコンテンツが明示的にドキュメントのアウトラインにリストされる場合にのみ適切だということです。

長々と引用しましたが使い方は簡単です。セクショニング・コンテンツは上の4つしかなくて、article要素、aside要素、nav要素はsection要素よりも目的がはっきりしているので、article、aside、navのどれかにあてはまりそうならそれを、どれにもあてはまらないのならsection要素を使えばいい んです。「article要素とsection要素のどちらを使うべきか」みたいなことを書いてるページがありますが、そういう人は上のリンク先を読み直した方がいいです。articleの例がちゃんと書いてありますから。

まとめ

HTML5でのコーディングで大事なのはセクションを意識したコーディングをするということです。出来上がったコードがきちっとした論理構造をもってるか、HTML 5 Outlinerでアウトラインを確認しましょう。