【自分用】HTMLのコンテンツモデルとカテゴリー

## 書こうと思ったきっかけ
マークアップエンジニアとしての自負はあるものの、たまに「このタグの中に、このタグを入れて良いのだっけ…？」とか、自分でも迷うことがあり、自分用も兼ねて書き起こしておくことにしました。
あと、初学者や過去の現場でマークアップにまるで頓着のないサーバーサイドエンジニアの方が

```html
<ul>
  <div>
    <li></li>
  </div>
</ul>
```
上記の様なマークアップをされてて「気持ち悪い…」と思っても、なぜ気持ち悪いのか上手く説明できないから、自身の知識の補填のためでもあります。

:::note warn
これはmdn web docsの内容を自分なりにまとめた内容です。
より詳しい内容を読みたければ[本家のページ](https://developer.mozilla.org/ja/)を参照ください。
:::

## HTMLのカテゴリー
HTMLの要素にはカテゴリーが存在していて、各要素に対するコンテンツモデルを定義するときに使用されます。

|カテゴリー名|カテゴリーの説明|属するHTML要素|
|:---|:---|:---|
|メタデータコンテンツ|メタデータコンテンツのカテゴリーに属する要素は、表示方法や文書のその他の部分の挙動を変化させたり、他の文書へのリンクを確立させたり、その他の本文外の情報を伝えたりします。|base, link, meta, noscript, script, style, title|
|フローコンテンツ|フローコンテンツは、body要素の中に入ることができるほとんどの要素を含む広いカテゴリーで、見出し要素、区分要素、記述要素、埋め込み要素、対話的要素、フォーム関連要素などが含まれます。また、テキストノードも含まれます（ただし、ホワイトスペースのみで構成されるものは除きます）。| a, abbr, address, article, aside, audio, b, bdo, bdi, blockquote, br, button, canvas, cite, code, data, datalist, del, details, dfn, div, dl, em, embed, fieldset, figure, footer, form, h1, h2, h3, h4, h5, h6, header, hgroup, hr, i, iframe, img, input, ins, kbd, label, main, map, mark, math, menu, meter, nav, noscript, object, ol, output, p, picture, pre, progress, q, ruby, s, samp, script, section, select, small, span, strong, sub, sup, svg, table, template, textarea, time, u, ul, var, video, wbr<br>特定の条件が満たされている場合のみ、このカテゴリーに属する要素がいくつか存在します。<br>area要素: map要素の子孫の場合<br>link: itemprop属性がある場合<br>meta: itemprop 属性がある場合|
|区分コンテンツ|区分コンテンツ (sectioning content) のモデルに属する要素はheader要素、footer要素、そして見出しコンテンツのスコープを定義する現在のアウトライン内のセクションを作成します。|article, aside, nav, section |
|見出しコンテンツ|見出しコンテンツ (heading content) は明示的に区分コンテンツ要素によってマークアップされたか、もしくは、見出しコンテンツ自身によって明示的に定義されたセクションの見出しを定義します。| h1, h2, h3, h4, h5, h6|
|記述コンテンツ|記述コンテンツ (phrasing content) は、文章とその中に含まれるマークアップを定義します。記述コンテンツの集まりで段落を構成します。| abbr, audio, b, bdo, br, button, canvas, cite, code, data, datalist, dfn, em, embed, i, iframe, img, input, kbd, label, mark, math, meter, noscript, object, output, picture, progress, q, ruby, samp, script, select, small, span, strong, sub, sup, svg, textarea, time, u, var, video, wbr および通常の文字列です（ホワイトスペースだけで構成されたものを除く）。|
|埋め込みコンテンツ|埋め込みコンテンツ (Embedded content) は、文書に他のリソースを取り込んだり、他のマークアップ言語や名前空間を挿入したりするものです。| audio, canvas, embed, iframe, img, math, object, svg, video|
|対話型コンテンツ|対話型コンテンツ (interactive content) にはユーザとのやり取りのために固有にデザインされた要素が含まれます。| a, button, details, embed, iframe, label, select, textarea<br>要素によっては、特定の条件下にある場合にのみこのカテゴリーに所属します<br>audio: controls 属性がある場合<br>img: usemap 属性がある場合<br>input: type 属性が hidden 状態ではない場合<br>menu: type 属性が toolbar 状態ではない場合<br>object: usemap 属性がある場合<br>video: controls 属性がある場合|


他にもフォーム関連コンテンツ等あります。
（非推奨のタグは記載していません）

出典:[mdn web docs コンテンツカテゴリー](https://developer.mozilla.org/ja/docs/Web/HTML/Content_categories)

## コンテンツモデルとは
> コンテンツ・モデルとはどの要素（タグ）にどんなコンテンツを入れて良いかを定義したものをいいます。すべての要素に定義されており、HTML5でマークアップする場合は、コンテンツ・モデルを意識する必要があります。

出典:[ゼロからはじめるHTML5でのサイト制作／第7回　HTML5の「コンテンツ・モデル」についてまとめよう](ゼロからはじめるHTML5でのサイト制作／第7回　HTML5の「コンテンツ・モデル」についてまとめよう)

では実際にどうやってコンテンツモデルを調べるか、mdnの要素のページを見ながらやっていきましょう。

### コンテンツモデルの調べ方

**例１：[`<p>`：段落要素](https://developer.mozilla.org/ja/docs/Web/HTML/Element/p)**

要素の説明にある「許可されている内容」に注目してください。
そこには「記述コンテンツ」と書かれています。
![スクリーンショット_2023-06-30_1_32_21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3443/6ec0bc97-309f-e97b-a788-c83ee456366e.png)
つまり、p要素の中に書いて良いのは記述コンテンツになります。
続いてa要素を見てみましょう。

**例２:[`<a>`: アンカー要素](https://developer.mozilla.org/ja/docs/Web/HTML/Element/a)**

![スクリーンショット_2023-06-30_1_57_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3443/8dca84a5-6f71-4035-eb90-1067b45c34bb.png)

コンテンツカテゴリーを見ても「え、どれ…？」ってなりませんでしたか？（私はなりました）
ただ「許容されている内容」を見ると`透過的コンテンツ、ただし子孫に 対話型コンテンツ または a 要素をがないもの、および tabindex 属性が指定された子孫がないもの。`と書かれてあります。

### 透過的コンテンツ
mdnの説明文を読んでも、ちょっと分からなかったので今度はHTML Living Standardの方を見てみましょう。
> いくつかの要素は透過的といわれる。コンテンツモデルの説明でそれらの要素は"透過的"とされる。透過的な要素のコンテンツモデルは、その親要素のコンテンツモデルを受け継ぐ。"透過的"であるコンテンツモデルの役割で要求される要素は、透過的な要素がある、透過的な親要素のコンテンツモデルの役割で要求されるものと同じ要素である。

出典:[3.2.5.3 透過的なコンテンツモデル](https://momdo.github.io/html/dom.html#transparent-content-models)
つまり、a要素は透過的コンテンツで、透過的コンテンツというのは親要素のコンテンツモデルを引き継ぐ、という意味になります。

```html
<div>
    <a href=""> <!-- このa要素は親のdiv要素のコンテンツモデルを引き継いでいるので中にpタグを入れて良い -->
       <p>テキスト</p>
    </a>    
</div>
```
ただ、許可されている内容を見る限り引き継いだからといって子要素には対話型コンテンツはNGです。
「a要素が透過的コンテンツモデルなのは分かった。じゃあ親要素がなかったらどうなんの？」
その場合はフローコンテンツになります。

> 透過的なコンテンツが親を持たない場合、"透過的"であるそのコンテンツモデルの役割は、代わりに任意のフローコンテンツを受け入れるものとして扱われなければならない。
出典:3.2.5.3 透過的なコンテンツモデル

例１や例２の様な感じでコンテンツモデルで迷ったらmdnやLiving Standardの仕様書を読むのが一番早いと思います。

## 最後に
ちょっとだけ軽く調べて記事を書くつもりが、調べれば調べるほど知らない単語が出てきたりして自分の知識の足りなさを痛感しました。
HTMLは出鱈目に書いてもそれなりに表示されます。
ただ、最近はアクセシビリティ対応が義務化になる動きなどもあるので、HTMLの文書構造についてもしっかりと勉強していく必要がありそうです。

この記事に関しても間違ってる可能性があるので、その際はコメントお待ちしております！！


## 参考
[2024年6月にWebアクセシビリティが義務化される？](https://www.idanet.co.jp/blog/web-accessibility/)

https://qiita.com/chimayu/items/2298164f275a0b195c9b