一覧WB-06-1 · HTMLの文書構造

HTMLの文書構造

勉強会の案内を同じ文書の中で組み立てます。文書全体の設定、意味を持つ要素、見出しの階層、段落の入れ子を順に変更し、DOMの出力と右側のプレビューを対応させます。docは解析した文書、treeは要素と文字ノードを階層表示する関数です。

説明

HTMLは文字を大きくしたり並べたりするだけの形式ではなく、見出し・段落・主な内容などの意味を要素で表す言語です。ブラウザはHTMLを解析してDOMという木構造を作り、その構造とスタイルから画面を描きます。

勉強会の案内を同じ文書の中で組み立てます。文書全体の設定、意味を持つ要素、見出しの階層、段落の入れ子を順に変更し、DOMの出力と右側のプレビューを対応させます。docは解析した文書、treeは要素と文字ノードを階層表示する関数です。

1HTML文書を解析

DOCTYPE、言語、文字コード、title、本文を持つHTMLをDOMParserで解析します。

(globalThis.doc=new DOMParser().parseFromStringHTMLをDOMへ解析('<!doctype html><html lang="ja"><head><meta charset="utf-8"><title>勉強会の案内</title></head><body><div id="heading">勉強会の案内</div><p>土曜日に図書室で開催します。</p></body></html>',"text/html"),{doctype:doc.doctype.nameDOCTYPE,lang:doc.documentElement.lang文書の言語,charset:doc.querySelector("meta").getAttribute("charset"),title:doc.title文書名})

htmlが文書全体、headが文書の設定、bodyが本文です。titleはタブなどの文書名として使われ、本文内の見出しとは別です。DOCTYPEは標準モードの指定に関わります。ここでのcharset属性はHTMLファイルをUTF-8として解釈するための宣言で、すでにあるJavaScript文字列を再符号化する操作ではありません。

2本文の木構造

bodyの子にある要素と、その中の文字を表示します。

tree(doc.body)本文の要素と文字ノード

bodyの下にはdivとpがあり、それぞれが文字ノードを持ちます。HTMLのタグそのものと、表示される文字ノードは別です。treeの字下げは親子関係を表しています。

3見た目の題名を見出し要素へ

題名に使っていたdivをh1へ置き換えます。文字列とidは引き継ぎます。

(globalThis.h=doc.createElement("h1")見出し要素を作成,h.id="heading",h.textContent文字を設定=doc.getElementById("heading").textContent,doc.getElementById("heading").replaceWith(h)元の要素を置換,h.outerHTML)

題名がh1となり、ブラウザの既定スタイルでも大きく表示されます。大きさだけをCSSで変えたdivと違い、文書の見出しであるという意味を持ちます。見出し要素の選択と、文字サイズの調整は別の設計です。

4文書の主要な領域を作る

題名、目次、主な内容、連絡先をそれぞれの要素で構成します。

(doc.body.innerHTML本文構造を置換='<header><h1>勉強会の案内</h1><nav aria-label="ページ内"><a href="#schedule">開催予定</a></nav></header><main><article><h2>初めて参加する方へ</h2><p>土曜日に図書室で開催します。</p><section id="schedule"><h3>開催予定</h3><p>13時から説明、14時から演習です。</p></section></article></main><footer>連絡先:図書室の受付</footer>',tree(doc.body)新しい親子関係を確認)

mainはこのページの主な内容、navは案内用のリンク群、articleは独立して扱えるまとまり、sectionは題のある節です。headerとfooterは置いた場所に応じてページや節の導入・末尾を表します。見た目の枠を増やしたいだけなら、意味が合わない要素を選ぶ必要はありません。

5見出しの順序と階層

h1・h2・h3を文書内の順序で取得します。

[...doc.querySelectorAll("h1,h2,h3")文書順の見出し].map(e=>({level:e.localName要素が持つレベル,text:e.textContent}))

h1が案内全体、h2が参加者向けの内容、h3がその中の開催予定です。sectionやarticleで囲めば、h1のレベルが自動的に下がると考えず、見出し自体のレベルを明示します。

6段落の中で重要性を表す

開催予定の段落に、重要な持ち物と時間を加えます。

(doc.querySelector("#schedule p").innerHTML段落内の要素を設定='開始は<time datetime="2026-11-14T13:00:00+09:00">11月14日13時</time>です。<strong>筆記用具を持参してください。</strong>演習は<em>自分で操作して</em>進めます。',doc.querySelector("#schedule p").outerHTML要素ごとの指定を表示)

timeのdatetimeは機械が解釈できる日時、strongは重要性、emは強調を表します。太字・斜体は既定表示の一例であり、見た目だけを目的に意味の違う要素へ置き換えるものではありません。

7文字としての記号とHTML

持ち物の表示に<と&を文字として含めます。

(doc.querySelector("#schedule p").textContent=文字列として設定'持ち物は「PC < 2台」と「筆記用具 & メモ」です。',{text:表示内容の文字doc.querySelector("#schedule p").textContent,html:HTMLとしての表現doc.querySelector("#schedule p").innerHTML})

textContentは文字を設定するため、<や&をタグの開始として解釈しません。innerHTMLとして読むと&lt;と&amp;が現れます。画面に表示する文字と、HTMLとして直列化した表現は異なります。

8pへ入れられない要素

pの中にdivを置いたHTMLを解析させます。

(doc.querySelector("#schedule").innerHTML='<h3>開催予定</h3><p>前半<div>演習</div>後半</p>'pの中へdivを置いた入力,tree(doc.querySelector("#schedule"))解析後の実際のDOM)

DOMではpがdivの前で閉じられ、divの後の「後半」はpの外へ出ます。末尾には空のpも作られます。ブラウザのHTML解析には誤りを補う規則があり、書いたタグの入れ子がそのままDOMになるとは限りません。

9段落とまとまりを正しく分ける

前半・演習・後半をそれぞれのまとまりとして書き直します。

(doc.querySelector("#schedule").innerHTML適切な親子関係へ修正='<h3>開催予定</h3><p>前半は説明です。</p><div><p>演習ではPCを使います。</p></div><p>後半は質問を受け付けます。</p>',tree構造を再確認(doc.querySelector("#schedule")))

各pは文字内容を持ち、演習のpだけがdivの中です。divは意味を特に追加しないまとまりとして使っています。文章の段落を分けるときはpを使い、見た目の空行を作るためだけにbrを重ねる設計は避けます。

10文字列中の空白と表示

同じ空白と改行を持つ文字列をpとpreに置きます。

(globalThis.p=doc.createElement("p"),globalThis.pre=doc.createElement("pre"),p.textContent="A B\nC"空白三つと改行を含む文字列,pre.textContent=p.textContent同じ文字列をpreへ,doc.querySelector("#schedule").append(p,pre),{p:p.textContent,pre:pre.textContent,same:p.textContent===pre.textContent文字データの一致})

文字列は同じですが、プレビューでは通常のpの空白がまとめられ、preは空白と改行を保ちます。DOMの文字データと、CSSのwhite-spaceによる表示処理を分けて考える必要があります。

11文書の意味を最後に確認

主な領域と見出しをまとめて確認します。

({mainCount:主な内容の領域数doc.querySelectorAll("main").length,headingCount:見出し数doc.querySelectorAll("h1,h2,h3").length,language:文書の言語doc.documentElement.lang,title:doc.title})

主な内容のmainは一つ、見出しは三つで、言語jaと文書名も残っています。画面だけでなく、文書の構造として何を伝えているかを確認します。langは読み上げなどの言語判断にも使われます。

まとめ

HTMLの文書設定、本文の意味構造、CSSによる見た目は役割が異なります。

要素の入れ子が不適切な場合、ブラウザが補ったDOMは入力したタグ列と異なることがあります。

文字ノード・見出しレベル・主要領域をDOMで確認し、プレビューの表示と対応させます。

操作履歴と解説を振り返れます。

ブラウザ / HTML・DOM

1
(globalThis.doc=new DOMParser().parseFromString('<!doctype html><html lang="ja"><head><meta charset="utf-8"><title>勉強会の案内</title></head><body><div id="heading">勉強会の案内</div><p>土曜日に図書室で開催します。</p></body></html>',"text/html"),{doctype:doc.doctype.name,lang:doc.documentElement.lang,charset:doc.querySelector("meta").getAttribute("charset"),title:doc.title})
{
  "doctype": "html",
  "lang": "ja",
  "charset": "utf-8",
  "title": "勉強会の案内"
}
2
tree(doc.body)
[
  "body",
  "  div#heading",
  "    \"勉強会の案内\"",
  "  p",
  "    \"土曜日に図書室で開催します。\""
]
3
(globalThis.h=doc.createElement("h1"),h.id="heading",h.textContent=doc.getElementById("heading").textContent,doc.getElementById("heading").replaceWith(h),h.outerHTML)
"<h1 id=\"heading\">勉強会の案内</h1>"
4
(doc.body.innerHTML='<header><h1>勉強会の案内</h1><nav aria-label="ページ内"><a href="#schedule">開催予定</a></nav></header><main><article><h2>初めて参加する方へ</h2><p>土曜日に図書室で開催します。</p><section id="schedule"><h3>開催予定</h3><p>13時から説明、14時から演習です。</p></section></article></main><footer>連絡先:図書室の受付</footer>',tree(doc.body))
[
  "body",
  "  header",
  "    h1",
  "      \"勉強会の案内\"",
  "    nav",
  "      a",
  "        \"開催予定\"",
  "  main",
  "    article",
  "      h2",
  "        \"初めて参加する方へ\"",
  "      p",
  "        \"土曜日に図書室で開催します。\"",
  "      section#schedule",
  "        h3",
  "          \"開催予定\"",
  "        p",
  "          \"13時から説明、14時から演習です。\"",
  "  footer",
  "    \"連絡先:図書室の受付\""
]
5
[...doc.querySelectorAll("h1,h2,h3")].map(e=>({level:e.localName,text:e.textContent}))
[
  {
    "level": "h1",
    "text": "勉強会の案内"
  },
  {
    "level": "h2",
    "text": "初めて参加する方へ"
  },
  {
    "level": "h3",
    "text": "開催予定"
  }
]
6
(doc.querySelector("#schedule p").innerHTML='開始は<time datetime="2026-11-14T13:00:00+09:00">11月14日13時</time>です。<strong>筆記用具を持参してください。</strong>演習は<em>自分で操作して</em>進めます。',doc.querySelector("#schedule p").outerHTML)
"<p>開始は<time datetime=\"2026-11-14T13:00:00+09:00\">11月14日13時</time>です。<strong>筆記用具を持参してください。</strong>演習は<em>自分で操作して</em>進めます。</p>"
7
(doc.querySelector("#schedule p").textContent='持ち物は「PC < 2台」と「筆記用具 & メモ」です。',{text:doc.querySelector("#schedule p").textContent,html:doc.querySelector("#schedule p").innerHTML})
{
  "text": "持ち物は「PC < 2台」と「筆記用具 & メモ」です。",
  "html": "持ち物は「PC &lt; 2台」と「筆記用具 &amp; メモ」です。"
}
8
(doc.querySelector("#schedule").innerHTML='<h3>開催予定</h3><p>前半<div>演習</div>後半</p>',tree(doc.querySelector("#schedule")))
[
  "section#schedule",
  "  h3",
  "    \"開催予定\"",
  "  p",
  "    \"前半\"",
  "  div",
  "    \"演習\"",
  "  \"後半\"",
  "  p"
]
9
(doc.querySelector("#schedule").innerHTML='<h3>開催予定</h3><p>前半は説明です。</p><div><p>演習ではPCを使います。</p></div><p>後半は質問を受け付けます。</p>',tree(doc.querySelector("#schedule")))
[
  "section#schedule",
  "  h3",
  "    \"開催予定\"",
  "  p",
  "    \"前半は説明です。\"",
  "  div",
  "    p",
  "      \"演習ではPCを使います。\"",
  "  p",
  "    \"後半は質問を受け付けます。\""
]
10
(globalThis.p=doc.createElement("p"),globalThis.pre=doc.createElement("pre"),p.textContent="A B\nC",pre.textContent=p.textContent,doc.querySelector("#schedule").append(p,pre),{p:p.textContent,pre:pre.textContent,same:p.textContent===pre.textContent})
{
  "p": "A   B\nC",
  "pre": "A   B\nC",
  "same": true
}
11
({mainCount:doc.querySelectorAll("main").length,headingCount:doc.querySelectorAll("h1,h2,h3").length,language:doc.documentElement.lang,title:doc.title})
{
  "mainCount": 1,
  "headingCount": 3,
  "language": "ja",
  "title": "勉強会の案内"
}

演習完了