Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第9章 img はなぜ閉じタグを持たないのか

内容を囲む p や div と違って、img には終了タグを書けません。p では条件付きで終了タグを省略できますが、img は別の分類です。書き忘れても怒られないどころか、</img> と書くほうが間違いです。なぜ画像だけ、特別扱いなのでしょうか。

この章では、img に閉じタグがないのは書き忘れを許しているからではなく、最初から子を持たない要素として設計されているからだと見ます。

9.1 img は内容を包む要素ではない

p や div を見ると、開始タグと終了タグのあいだに内容が入るのが HTML の基本形に見えます。その感覚のまま img を見ると、「なぜここだけ閉じタグがないのか」と不思議に見えます。

しかし img は、文章や子要素を内側に抱える要素ではありません。文書の中に画像という外部資源を埋め込む場所を示す要素です。必要なのは、どの画像を参照するか、代替テキストをどう与えるかといった属性であって、開始タグと終了タグのあいだに入る本文ではありません。

ここで重要なのは、img が「中身を書かなくてもよい要素」なのではないことです。最初から子を持てない要素として定義されているので、閉じタグが省略されているのではなく、そもそも持たないのです。

9.2 空要素という区別

HTML には、img のほかにも br hr meta link input のように、子を持たない要素があります。これらは空要素として扱われます。

<p>前置き<br>補足</p>
<img src="photo.jpg" alt="港の写真">

この例で br は改行位置を、img は画像の埋め込み位置を表しています。どちらも、あいだに文章や別要素を抱えて意味を作る要素ではありません。だから </br> や </img> のような終わり方を期待するより先に、「この要素は内容を囲む型なのか、位置だけを示す型なのか」を見分ける必要があります。

第1章で、HTML は処理を書く言語ではなく文書構造を記述する言語だと見ました。その観点から読むと、空要素は「ここに何かがある」という構造上の印を置く要素です。文を開いて閉じる箱ではなく、文書の中に特定の役割を持つ点を打つ要素だと考えたほうが実態に近いです。

ここで見えてくるのは、HTML が「タグごとに見た目の書き方が違う言語」なのではなく、「要素ごとに持てる内容を分類している言語」だということです。閉じタグの有無は、その分類の結果として表に出ているにすぎません。

9.3 <img /> は HTML では何を意味するのか

ここでよく混乱するのが、<img /> という書き方です。XML や XHTML に慣れていると、自己終了記法に見えます。そのため、「HTML でも末尾の / が要素を閉じている」と理解したくなります。

しかし HTML では、本質はそこではありません。img が閉じタグを持たないのは、末尾の / があるからではなく、img 自体が空要素だからです。つまり img の終わりを決めているのは見た目の記号ではなく、要素の定義です。

この違いを見失うと、「では <div /> も同じように閉じられるのか」と考えてしまいます。HTML ではそうはなりません。

<div />
<p>本文</p>

これを「div がここで閉じた」と読むと分かりやすそうですが、HTML ではそうした自己終了にはなりません。div は空要素ではないので、/ が付いていても、通常要素として扱われます。子を持つ通常要素と、最初から子を持てない空要素は、見た目が少し似ていても文法上は別物です。/ が魔法の閉じ記号なのではなく、空要素にたまたま付いていても害が出にくいだけだ、と理解したほうが正確です。

補足: 1993 年の www-talk で、Marc Andreessen は画像を文書内に埋め込む IMG タグを提案しました。現在の img のすべての設計理由が、その一通で決まったわけではありません。提案と現在の仕様を分けて読むことが大切です。

もう 1 つ: 「<div /> の / は無視される」と書きましたが、これには例外があります。HTML の中に埋め込んだ SVG や MathML(外来要素) の中では、<rect /> のような自己終了が本当に効きます。これらは XML 由来の文法を持つためです。つまり / が無意味なのは「HTML の通常要素では」という条件付きで、同じ 1 文字が、文脈によって効いたり効かなかったりします。

9.4 終了タグがないことは「ゆるさ」ではない

img に閉じタグがないと聞くと、HTML のゆるさの例に見えがちです。しかし実際には逆です。何でもありだから閉じタグがないのではなく、子を持たない要素を最初から区別しているから、ここでは閉じタグが不要になります。

この視点は、第2部で見てきた HTML の挙動にもつながります。HTML は入力に寛容な場面がある一方で、内部では要素ごとの役割や置ける内容をかなりはっきり区別しています。img が閉じタグを持たないのも、その区別の一部です。ゆるい書式の偶然ではなく、コンテンツモデル(要素ごとに「中に何を置けるか」を定めたルール)を持つ文法の結果として読むべきです。

実務でも、この理解は無駄ではありません。たとえばテンプレートを読んでいるときに、img を p や div と同じ感覚で眺めると、「なぜここは閉じていないのか」という枝葉に引っ張られます。先に「これは内容を包む要素ではない」と分かっていれば、見るべき関心は閉じ方ではなく、src や alt など、その要素に本当に必要な情報へ向きます。

ここまでで、閉じタグの有無は書き方の癖ではなく、要素がどんな内容を持てるかという設計の結果だと分かりました。次章では、その視点をさらに地味な題材へ移し、コメントでさえ好き勝手に書けるわけではないことを見ます。

9.5 同じスラッシュでも処理系を確認する

処理系空の div空要素 img
HTML(text/html)<div></div>。<div /> は自己終了しない終了タグを書かない
XML としての XHTML<div /> で空要素として閉じられるXML の規則で <img … /> または終了タグを使う
React の JSX<div /> で内容なしを表せる<img … /> のように閉じる必要がある

JSX はブラウザの HTML パーサーへ直接渡す構文ではありません。また HTML では、引用符なしの属性値に続く / にも注意が必要です。

<img alt="港" src=photo.jpg/>
<img alt="港" src="photo.jpg" />

最初の src の値は photo.jpg/ です。二つ目の値は photo.jpg で、末尾のスラッシュは値の外にあります。属性値を引用符で囲むと、この境界を読み取りやすくなります。

参考資料