HTML のフォーム送信に使われたボタンを判別する ― 2021年12月16日 23時00分
この記事は HTML アドベントカレンダーの 16 日目の分、兼 JavaScript アドベントカレンダーの 16 日目の分です。
HTML のフォームには複数の送信ボタンを設置できます。ある送信ボタンを実行してフォームを送信すると、その送信ボタンの name
属性と (送信ボタンが button
要素なら) value
属性の値も送信データに含まれます。
どの送信ボタンを実行してフォームを送信したのか、JavaScript からは submit
イベントに紐づく SubmitEvent
オブジェクトの submitter
プロパティで判別できます。以下の例では、「公開する」または「削除する」ボタンを実行すると、JavaScript コンソールにそのボタンが出力されます。
<form
method="post"
action="/edit"
onsubmit="console.log(event.submitter); return false;">
<p>
<button type="submit" name="publish" value="1">公開する</button>
<button type="submit" name="delete" value="1">削除する</button>
</p>
</form>
submitter
プロパティが実装される前は、各ボタンの click
イベントを基に、どのボタンが最後に実行されたのか記憶しておく必要がありました。そこからするとずいぶん楽になりましたね。
HTML の iframe 要素の srcdoc 属性で埋め込まれる文書の URL ― 2021年12月15日 23時21分
この記事は HTML アドベントカレンダーの 15 日目の分です。
iframe
要素 のsrcdoc
属性の値に HTML 文書のソースコードを記述すると、その HTML 文書を埋め込んだフレームが生成されます。ここで、埋め込まれた HTML 文書の URL はどうなっているでしょうか。
<!-- iframe 要素を含む文書の URL は https://www.example.com/ であるとする。 -->
<iframe srcdoc="
<a href="foo?bar=42&amp;baz=23">Link</a>
<script>
console.log(location.href);
// => "about:srcdoc"
console.log(document.querySelector('a').href);
// => "https://www.example.com/foo?bar=42&baz=23"
</script>
"></iframe>
埋め込まれた文書の URL は about:srcdoc
ですが、その文書内のリンクにおいては「iframe
要素を含む文書の URL」を基底 URL として相対 URL が解決されます。
base
要素を使えば文書の URL と異なる URL を基底 URL として使えますが、srcdoc
属性を使って埋め込まれた文書では base
要素がなくてもそのような状態になっているのですね。<iframe src="about:blank">
で埋め込まれた文書も同様の状態になります。
ちなみに、srcdoc
属性で埋め込まれた HTML 文書では文書型宣言 (<!DOCTYPE html>
) が省略可能であり、省略した場合も標準準拠モードで描画されます。また、title
要素も省略可能となります。html
、head
、body
の各要素の開始タグおよび終了タグはもともと省略可能なため、body
要素の内容が「body
要素内にしか出現しえない要素」から始まるのなら、その要素の開始タグから記述を開始できます。
HTML の属性値とテキストのパース結果の違い ― 2021年12月14日 23時24分
この記事は HTML アドベントカレンダーの 14 日目の分です。
HTML の属性値のパース規則は、(一般的な要素の内容として出現する) テキストのパース規則とは少し異なります。
わかりやすいところでは、属性値においては小なり記号 (<
) をそのまま書けます。以下の HTML コードにおいて、span
要素の title
属性の値も内容のテキストも結果的には " < "
という値になりますが、テキストに関しては内部的にパースエラー (invalid-first-character-of-tag-name; タグの名前の 1 文字目が無効) が発生しています。
<span title=" < "> < </span>
文字参照の扱いにも差異があります。以下のように amp
という文字参照の名前の後に ASCII の英数字が続く場合、属性値においては "&m"
という値に解釈されます。一方、テキストにおいては &
が不完全な文字参照とみなされ、内部的にパースエラー (missing-semicolon-after-character-reference; 文字参照の後にセミコロンがない) が発生しつつ "&m"
という値に解釈されます。
<span title="&m">&m</span>
この解釈の違いは、文字参照の名前の後に等号 (=
) が来る場合も同様です。以下の例で、属性値は "&="
という値と解釈され、内容のテキストは内部的にパースエラーが発生しつつ "&="
という値に解釈されます。
<span title="&=">&=</span>
文字参照の名前の後に ASCII の英数字でも等号でもない文字が来る場合は、属性値でもテキストでも内部的にパースエラーが発生しつつ文字参照として扱われます。以下の例では共に "&*"
という値に解釈されます。
<span title="&*">&*</span>
このような属性値におけるアンパサンドの特殊な扱いにより、クエリパラメータ amp
、ampm
を含むような URL https://www.example.com/foo?bar=42&=23&m=12
を a
要素の href
属性の値にそのまま (&
を文字参照にせずに) 書いたとしても、リンク先 URL は (https://www.example.com/foo?bar&=23&m=12
ではなく) https://www.example.com/foo?bar=42&=23&m=12
になります。
<a href="https://www.example.com/foo?bar=42&=23&m=12">...</a>
しかしながら、このような特殊な扱いに依存した記述は意図しない挙動をもたらすことがあるため (属性値の URL をテキスト部分にコピペしたら値が変わってしまうなど)、属性値だろうがテキストだろうが &
を記述したいときは文字参照 &
を使うことをお勧めします。
HTML の透過的内容モデル ― 2021年12月13日 22時46分
この記事は HTML アドベントカレンダーの 13 日目の分です。
その昔、HTML 4 の時代には以下のようなコードは仕様違反でした。a
要素はインライン要素であり、その内容にブロックレベル要素である h3
要素は取れなかったからです。
<a href="url"><h3>見出し</h3></a>
現在の HTML 標準では、a
要素、ins
要素、del
要素などは内容モデルが透過的 (transparent) であるとされ、上述のコードも仕様に適合しています。
透過的内容モデルの要素は、その子要素から見ると透過的です。言い換えると、透過的内容モデルの要素が取れる内容は、その親要素が取れる内容を引き継ぎます。ある a
要素の親要素が div
要素なら、その a
要素の内容はフローコンテンツ (flow content) となります。親要素が p
要素なら、内容は記述コンテンツ (phrasing content) となります。
しかしながら、透過的内容モデルの要素は、その親要素から見ると透過的ではありません。透過的内容モデルの要素はどこにでも出現できるわけではないということです。a
要素、ins
要素、del
要素はいずれもフローコンテンツおよび記述コンテンツのカテゴリに属しており、フローコンテンツまたは記述コンテンツが出現できる個所にしか出現できません。以下のように表の行を囲んだりはできないのです。
<table>
<tbody>
<!-- a 要素の位置が不適切 -->
<a href="url">
<tr>
<td>cell</td>
<td>cell</td>
</tr>
</a>
</tbody>
</table>
a
要素がフローコンテンツを内容に取りうるといっても、a
要素に対するデフォルトスタイルシートは display: inline
のままであることに注意が必要です。ブラウザによっては display: inline
な要素の子要素に display: block
な要素があり、かつ flexbox や grid が複雑に絡み合ったときに、要素の高さの計算がまれに意図しない結果になるようです。子要素に display: block
な要素がくるときは、a
要素自身にも display: block
を指定しておいたほうが安全かもしれません。
HTML 標準における段落の概念 ― 2021年12月12日 21時41分
この記事は HTML アドベントカレンダーの 12 日目の分です。
以下の HTML コードを見て、なにか居心地の悪さを感じるでしょうか?
<h1>12日の日記</h1>
天気: 晴れ
<p>今日は動いた。</p>
筆者はどうも居心地の悪さを感じます。「天気: 晴れ」の部分が暗黙的な段落になっているのがその原因です。
HTML 標準において段落 (paragraph) とは、文や記述コンテンツの塊を表す概念です。p
要素は段落を明示しますが、p
要素だけでなく li
要素や div
要素なども段落を表現します。段落の内容が文章である必要はなく、「天気: 晴れ」といった行や住所表記、フォームの入力欄を含む行なども段落となります。
何らかの要素を使って段落を明示しないといけないという決まりはどこにもないのですが、HTML 4 Strict の時代は body
要素直下にブロック要素しかこれなかったこともあり、暗黙的な段落があると p
要素をつけたくなってしまいます。
HTML 4 時代を引きずっているという点では、form
要素の内容も気になります。HTML 4 Strict では form
要素直下にもブロック要素しかこれませんでした。以下のように form
要素直下に記述コンテンツ (phrasing content) が来ていると、
<form aciton="/search">
<p><label>検索語: <input type="search" name="q"></label></p>
<button type="submit">検索</button>
<input type="hidden" name="token" value="deadbeef">
</form>
すべて p
要素で囲みたくなります。
<form aciton="/search">
<p><label>検索語: <input type="search" name="q"></label></p>
<p>
<button type="submit">検索</button>
<input type="hidden" name="token" value="deadbeef">
</p>
</form>
最近のコメント