HTML のアウトラインアルゴリズムが見出しレベルをベースとしたものに刷新されそう

HTML のアウトラインアルゴリズムが刷新されようとしています。

本記事では、最初に現時点のアウトラインアルゴリズムの概要を説明した後、どのような変更が行われるかを紹介します。

  1. 現時点のアウトラインアルゴリズムの概要
  2. アウトラインアルゴリズムの刷新

現時点のアウトラインアルゴリズムの概要

§

HTML にはアウトラインアルゴリズムという概念があります。

一昔前の HTML、すなわち HTML4 以前はセクションの概念がなく、章立ては見出し要素(<h1><h6>)のみで行うしかありませんでした。

HTML5 ではアウトラインの概念が導入され、見出し要素とセクショニングコンテンツ(<section> 要素など)を組み合わせてセクションを使用することが可能になり、仕様では専用の章「Headings and sections」にて詳しく解説されています。

現時点(2022年4月21日現在)におけるアウトラインアルゴリズムでは以下の重要な概念があります。

  • 暗黙のセクションと明示的なセクション
  • セクションのレベルと見出しランク
  • セクショニングルート

暗黙のセクションと明示的なセクション

§

要するにセクショニングコンテンツを使うかどうかということです。昔ながらの見出し要素のみを使ったマークアップでは暗黙のセクションが自動的に作られることになりますが、 <section> 要素等を使い範囲を明示的に示すこともできます。例を挙げると、以下の3つの HTML はすべて等価に解釈されます。

<!-- 暗黙のセクション -->
<body>
	<h1>見出し 1</h1>

	<h2>見出し 2-1</h2>
	<h3>見出し 3-1</h3>

	<h2>見出し 2-2</h2>
</body>
<!-- 明示的なセクション(すべて `h1` 要素を使用する例) -->
<body>
	<h1>見出し 1</h1>

	<section>
		<h1>見出し 2-1</h1>

		<section>
			<h1>見出し 3-1</h1>
		</section>
	</section>

	<section>
		<h1>見出し 2-2</h1>
	</section>
</body>
<!-- 明示的なセクション(アウトラインの深さに応じて `h1` 〜 `h6` 要素を使い分ける例) -->
<body>
	<h1>見出し 1</h1>

	<section>
		<h2>見出し 2-1</h2>

		<section>
			<h3>見出し 3-1</h3>
		</section>
	</section>

	<section>
		<h2>見出し 2-2</h2>
	</section>
</body>

セクションのレベルと見出しランク

§

セクショニングコンテンツ要素を入れ子にすることで、任意の階層構造のアウトラインを構成することができます。

前述のマークアップ例はこのような構造になります。

見出し 1 (トップレベル)
 ├ 見出し 2-1 (第2レベル)
 │ └ 見出し 3-1 (第3レベル)
 └ 見出し 2-2 (第2レベル)

HTML4 以前は、見出し要素の数字が「level(レベル)」と呼ばれていました。今でも Web エンジニアの会話やスクリーンリーダーの発声で「見出しレベル1」などと呼ばれることがありますが、それは HTML4 の名残です。

しかしコード例にあるように、見出しをすべて <h1> 要素にすることもできますし、他にも「見出し 2-1」を <h3> 、「見出し 3-1」を <h6> のようにマークアップすることも可能であり、アウトラインを考える上でのレベルと見出し要素の数字は必ずしも一致しません。そのため HTML5 や HTML LS では見出し要素の数字に対して「rank(ランク)」(html.spec.whatwg.org)の単語が使われるようになりました。

セクショニングルート

§

<blockquote> などいくつかの要素は祖先のアウトラインとは独立した自身のアウトラインを持つとされているのですが、それをセクショニングルート(html.spec.whatwg.org)と呼びます。 <blockquote> 要素の中の見出しはあくまで引用元ソースの見出しであり、当該文書のアウトラインとは無関係だからです。このような要素は <body> 要素も含めて以下の7つが該当します。

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

このように、章立てを見出し要素のみで行うしかなかった HTML4 時代と比べればアウトラインアルゴリズムは画期的な概念と言えますが、残念ながらブラウザや支援技術の実装は進んでおらず、 Web コンテンツの制作者はそれに頼るべきではない状況です。具体的に言うと、前述の3パターンのコード例のうち、明示的なセクションで <h1> 要素のみを使用した2番目のマークアップは避けた方が良いです。

アウトラインアルゴリズムの刷新

§

そんな状況に対して、 W3C の HTML 仕様では HTML 5.1 において従来どおり <h1><h6> の見出しランクを使用すべきとの警告文が提示(www.w3.org)されましたが、 Living Standard では 2015年から issue で議論は行われている(github.com)ものの、現在に至るまでそのような記述は本文に盛り込まれていません。

画像1W3C HTML 5.1 の「4.3.10.1. Creating an outline」冒頭の警告文

また、現行のアウトラインアルゴリズムを廃止して見出し要素に焦点を当て、さらに CSS の :heading 疑似クラスを導入する議論(github.com)もありますが、ブラウザへの実装がうまくいっていないようで[1]、こちらも決着は付いていません。

そんな中、4月17日に stevefaulkner 氏が新たな PR を提出しました。

もっとも重要な部分である新たな「4.3 Sections」(whatpr.org)を中心に、注目すべき点を抜粋します。

  • まだ正式に仕様に反映されたわけではなく、今後内容が変更されたり、レビューで却下されたりする可能性があることにはご留意ください。

アウトラインアルゴリズムの削除

§

アウトラインアルゴリズムの記述はごっそり削除されました。セクショニングコンテンツと <h1> 要素を使ってアウトラインを作る構想は画期的ではありましたが、ブラウザの実装叶わず幻想に終わりました。

セクショニングルートの概念が消滅

§

アウトラインアルゴリズムの廃止に伴い、セクショニングルートの概念も消滅しました。とくに引用文で <blockquote> 要素内に見出し要素を含める場合、その見出しは HTML4 時代と同様に文書全体の見出しの一つとして解釈されるので注意しましょう。

見出しランク → 見出しレベル

§

前述のように見出し要素の数字は HTML5 以降、「ランク」の用語が使われていましたが、アウトラインアルゴリズムの廃止に伴い「レベル」に戻りました。

<h1> 要素はレベル1、<h2> 要素はレベル2、……となります。

`<h1>` 要素が事実上必須になる

§

一般論として Web ページ冒頭の見出しは <h1> 要素が適切であり、いきなり <h2> 以降から始まるのは好ましいことではありませんが、 HTML としてはとくに問題ありませんでした。

過去の HTML では、 HTML 2.0(RFC 1866)においてdocuments should not skip levels (for example, from H1 to H3)という記述があり、 <h1> をスキップするのもダメだと解釈できますが、これは HTML の歴史の中では例外的なもので、HTML 1.0 や HTML 3.2 など他のバージョンではそのような制約はありませんでした[2]

この度の PR では次の一文があります。

If a document has a heading, at least a single heading within document headings must have a heading level of 1.

すなわち、見出しの一切ない小規模なページや HTML メールなど特殊な事例を除けば、多くのケースでは <h1> 要素は事実上必須になるともいえます。 lint ツールを活用するなどして書き忘れがないようチェックしたいところです[3]

また、 <h1> 要素はあれば良いというものではなく、文書内の最初の見出しとなる必要があるため、次のようなマークアップは不適合となります。

<!-- これは NG な例です -->
<body>
	<header>
		<h2>ページヘッダー</h2>
	</header>

	<main>
		<h1>ページタイトル</h1>
	</main>
</body>

2022年7月5日追記7月1日に正式にマージされましたが、 PR 時点の must have から should have へと若干表現が緩くなりました。サンプルコード(html.spec.whatwg.org)でも <h1> 要素のない文書について「適合するが推奨されない(not encouraged)」という表現になっています。いずれにしても好ましくないことには変わりないので、基本的には <h1> 要素のない文書は避けるべきでしょう。

`<h1>` 要素の複数配置は可能

§

一般論として文書内の <h1> 要素は一つにとどめた方が良いでしょう。 MDN における見出し要素の解説では複数の <h1> 要素の使用(developer.mozilla.org)と題して突っ込んだ記述があります。

この度の PR ではアウトラインアルゴリズムは削除されたものの、A document can contain multiple top-level headings:と、<h1> 要素の複数配置は引き続き可能ということになっています。

意図して複数配置をするのならよいですが[4]、多くのケースでは <h1> 要素は一つに絞れると思うので、これも lint ツールを活用するとよいでしょう。

見出しレベルのスキップは順方向のみ可能(?)

§

Each heading following another heading lead in document headings must have a heading level that is less, equal, or 1 greater than lead's heading level.

なぜこのような定義になったのか経緯を追っておらず詳細は分かりませんが、 <h2><h4> のようなスキップは可能だが、逆は不可ということでしょうか。

`<hgroup>` 要素の定義が変更

§

<hgroup> 要素は引き続き有効です。 <hgroup> 要素を廃止する別の PR(github.com)も上がっていますが、本 PR では生き残っています。ただしアウトラインアルゴリズムが削除されたことから、その定義は大きく変更されました(whatpr.org)

現状はコンテンツモデルが <h1><h6> およびスクリプトサポート要素のみで、小見出しやキャッチコピーを表現するのに hgroup > h1 + h2 のような構造で使用されます。

この度の PR では「一つの見出し要素、オプションで一つ以上の <p> 要素、オプションでスクリプトサポート要素が混合」となっており、以下のような使い方となります。

<hgroup>
	<h1>見出し</h1>
	<p>小見出し</p>
</hgroup>

2022年7月5日追記7月1日に正式にマージされましたが、見出し要素の前にも <p> 要素を配置することが可能となりました。そのため、見出しより先に小見出しを置くことができます。


HTML 仕様のアウトラインアルゴリズムが現実に即していないことは前々から言われていましたが、この PR が取り込まれればやっと……といったところでしょう。

個人的には XHTML2 で <section> 要素と <h> 要素(www.w3.org)の組み合わせによる構造化を夢見た世代でもあるので、その残り香ともいえるアウトラインアルゴリズムの廃止には一抹の寂しさも感じますが、 UA にサポートされる見込みのないものが仕様に残り続ける現状は誰にとってもよろしくありません。また、これでようやく <hgroup> 要素の方向性が定まる期待もあります。

ともかくも、正式に仕様に反映されることを願うところです。