スポンサーリンク

JavaScriptの動かないコード (中級編) p要素への appendChild() で失敗する


クイズ…下記のJavaScriptコードが,意図した動作をしないのはどうしてですか。(制限時間1分)


やりたい事:
<p>タグの中に,div要素が1つ入っている。もう一つdiv要素を追加して,

<p id="target_tag">
  <div id="div_1">1つ目のdivです。</div>
  <div id="div_2">2つ目のdivです。</div>
</p>

というタグ構造にしたい。

<body>
<script language="JavaScript">

function f()
{
    // <div> タグを複製します。
    var element_div2 = div_1.cloneNode(false);
    element_div2.id = "div_2";
    element_div2.innerHTML = "2つ目のdivです。";

    // 上の要素を,<p> タグの中に追加します。
    target_tag.appendChild( element_div2 );
    //alert(document.body.innerHTML);
}

</script>

<input type="button" onClick="f()" value="クリックして要素を追加" />

<p id="target_tag"><div id="div_1">1つ目のdivです。</div></p>

</body>

発生する不具合と原因


p要素の中に,div要素を入れることはできない。


HTMLタグには,

  • ブロックレベル要素(特徴:「前後に改行を伴う」「四角で囲まれる」等)
  • インライン要素(特徴:文字列を装飾する等)

の2種類がある。


pもdivもブロック要素である。
divのような大抵のブロック要素には,ブロック要素も,インライン要素も入れ子で挿入できる。
しかし,pはブロック要素であるにも関わらず,子ノードとしてインライン要素しか持つことができない。(これはHTMLの決まりである。)


参照:ブロック要素とインライン要素
http://www.tagindex.com/html_tag/basi...


つまり,

<div><p></p></div>
とか
<div><div></div></div>

は,正しいHTMLだが,

<p><div></div></p>

は,無効なHTMLである。


冒頭のスクリプトを実行してから,body.innerHTMLを表示させてDOM構造を確かめると,

Firefoxでは

<p id="target_tag">
  <div id="div_2">2つ目のdivです。</div>
</p>
<div id="div_1">1つ目のdivです。</div><p></p>

のようになる。つまり,タグの入れ子構造を保ちつつも,不思議な入れ替わり現象が起きる。


IEでは

<p id="target_tag">
  <div id="div_2">2つ目のdivです。</div>
  <div id="div_1">1つ目のdivです。</div>
<p></p>

となり,タグの入れ子構造が崩壊する。


両者とも,画面での見かけ上は,いちおうdivタグの中身の文言が表示される。DOMアクセスを試みた段階で初めてエラーに気づくかもしれない。

修正案

この事態を避けるためには,appendChild()したい親要素(target_tag)を,pではなくdivなどにすればよい。