HTML5 で button 要素の中にフレージングコンテンツしか入れられなくなっていた

公開日:

何を今さらって話なんですけど、お恥ずかしながらさっき気づいたので。

その昔、 HTML4 では button要素 の中に p 要素や div 要素などを置くことが可能でした。DTD(www.w3.org)には以下のように定義されており、 %flow; とは %block; | %inline; を指します。

<!ELEMENT BUTTON - - (%flow;)* -(A|%formctrl;|FORM|FIELDSET) -- push button -->

これはつまり、

<p><button><div>p の中の button の中に div</div></button></p>

<p><button><p>p の中の button の中に p</p></button></p>

が正当であることを意味します。

おそろしいことに、こんなマークアップもできたんですね。

<p><button>
<table border="">
<caption>p の中のbutton の中に table</caption>
<thead>
<tr>
<th scope="col">セル</th><th scope="col">セル</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">セル</th><td>セル</td>
</tr>
</tbody>
</table>
</button></p>
図1:<button>の中にブロック要素を入れてみるテスト

ですが、 HTML5 や HTML Living Standard ではbutton 要素(html.spec.whatwg.org)のコンテンツモデルが「Phrasing content, but there must be no interactive content descendant.」とされたため、上記のマークアップは invalid となります。

でも、現実問題として button 要素の中に div や p を入れたいこと、ありますよねえ……。

リンクアンカーに関しては、 a 要素の中に div 要素を入れられるようになったため、タッチデバイスを意識して div 要素を使うボックス枠ごとクリッカブルにするデザインが簡単にできるようになりましたが、同じようにボックス枠自体をダイアログやアコーディオンを表示するフックとなるボタンにすることはできなくなりました。もちろん、 div 要素が適切であるところすべて span 要素にして、 CSS で display: block とかやれば、とりあえずマークアップとしては正当なものになりますが、うーんこのもやもや感。