HTML の form 要素の rel 属性2021年12月06日 23時00分

この記事は HTML アドベントカレンダーの 6 日目の分です。


HTML の link 要素や a 要素には rel 属性を指定できます。もともとは閲覧中の Web ページとリンク先のリソースの関係性を示すものでしたが、現在はリンクの挙動を指定するためにも使われています。rel="noreferrer" ならリンク先の文書にリファラーを送らない、rel="noopener" ならリンク先文書の JavaScript から元の文書へのアクセスを禁止する、といった挙動です。

これらの rel 属性の値は、a 要素だけでなく form 要素にも使えます。以下のようなフォームがあったとき、フォームを送信すると新たなタブ (またはウィンドウ) が開きますが、そのタブの JavaScript から window.opener プロパティで元のタブの文書を参照することはできません。

<form method="get" action="/search" target="_blank" rel="noopener">
  ...
</form>

2021 年 12 月現在、Safari の開発版では form 要素の rel 属性への対応が進んでいますが、Chorme と Firefox は対応していません。

参考文献

同じような HTML コードでもパース結果が異なることがある2021年12月05日 23時11分

この記事は HTML アドベントカレンダーの 5 日目の分です。


HTML 標準では、誤りのある HTML コードを Web ブラウザがどう解釈すべきかも定められています。例えば、span 要素の終了タグを書き忘れた場合、

const c = document.createElement('div');
c.innerHTML = '<p><span>foo</p><p>bar</p>';
console.log(c.innerHTML);
// => "<p><span>foo</span></p><p>bar</p>"

最初の段落が終了する地点で span 要素も終了すると解釈されました。ここで span 要素を b 要素に変えてみるとどうなるでしょう。

const c = document.createElement('div');
c.innerHTML = '<p><b>foo</p><p>bar</p>';
console.log(c.innerHTML);
// => "<p><b>foo</b></p><p><b>bar</b></p>"

最初の段落が終了する地点で b 要素がいったん終了するのは span 要素のときと同じですが、今度は 2 番目の段落の内容にも b 要素が登場します。span 要素も b 要素も要素のカテゴリや内容モデルは変わらないのに、どうしてこの差が生まれるのでしょうか。

HTML のパースにあたって、abbigcodeemfontinobrssmallstrikestrongttu の各要素は書式設定要素という分類に含まれ、誤りの訂正方法が他の要素とは異なってくるのです。

Web 製作者が意図していたであろう構造を再現するため、また過去のブラウザのパース結果との互換性をできるだけ保つため、HTML パーサーはあれこれがんばって誤りを修正してくれているのですね。

HTML の dl 要素内のグループを明示する2021年12月04日 23時34分

この記事は HTML アドベントカレンダーの 4 日目の分です。


HTML の dl 要素 (説明リスト、いわゆる定義リスト) は、名前と値 (用語と説明) からなるグループの連なりを表します。ひとつのグループには dt 要素と dd 要素がそれぞれひとつ以上含まれます。

よく見るのは dl 要素の直下に dt 要素と dd 要素が来る形でしょう。以下の例では dl 要素にふたつのグループが含まれます。

<dl>
  <dt>琥珀</dt>
  <dd>寒天を使い透明感のある菓子の総称。</dd>
  <dd>琥珀糖のこと。</dd>

  <dt>琥珀糖</dt>
  <dt>干琥珀</dt>
  <dd>寒天を煮て固め表面を乾燥させた菓子。シャリっとした表面とプルっとした中身の対比が癖になる。</dd>
</dl>

スタイルシートを適用したり、マイクロデータの項目を作成したりするために、グループひとつずつを表す要素が欲しくなるかもしれません。そのときは div 要素を使ってグループを明示できます。

<dl>
  <div>
    <dt>琥珀</dt>
    <dd>寒天を使い透明感のある菓子の総称。</dd>
    <dd>琥珀糖のこと。</dd>
  </div>
  <div>
    <dt>琥珀糖</dt>
    <dt>干琥珀</dt>
    <dd>寒天を煮て固め表面を乾燥させた菓子。シャリっとした表面とプルっとした中身の対比が癖になる。</dd>
  </div>
</dl>

dl 要素に含まれるグループを明示したいという要望は昔からあり、XHTML2 では di 要素が定義されていました。HTML5 に対しても di 要素 (または dli 要素) が何度も提案されましたが、スタイルに関することはスタイルシートで解決すべきという意見、および新要素を導入すると従来の HTML パーサでは意図しない結果になるという問題から、そのたびに見送られてきました。

最終的に、div 要素を使えば従来の HTML パーサでも問題なく、またブラウザのデフォルトスタイルシートの影響も受けづらいということで、div 要素を使う案が採用されました。

参考文献

HTML のフォームの送信ボタンごとに挙動を変える2021年12月03日 21時29分

この記事は HTML アドベントカレンダーの 3 日目の分です。


フォームの送信先 URL や送信に使う HTTP メソッドは、基本的には form 要素の属性に記述します。送信先 URL なら action 属性、HTTP メソッドなら method 属性ですね。

しかし、ときには「この送信ボタンを実行したときだけ、通常と違う送信先 URL に送信したい」と思うかもしれません。それを実現するのが送信ボタン (<button type="submit"> 要素や <input type="submit"> 要素など) の formaction 属性です。

以下の例では、「保存する」ボタンを実行すると URL /edit に送信されますが、「削除する」ボタンを実行すると URL /delete に送信されます。

<form method="post" action="/edit">
  ...
  <p>
    <button type="submit">保存する</button>
    <button type="submit" formaction="/delete">削除する</button>
  </p>
</form>

formaction 属性以外にも formmethodformtargetformenctypeformnovalidate 属性が存在し、それぞれ form 要素の methodtargetenctypenovalidate 属性の値を上書きできます。

HTML のフォームコントロール要素をフォーム外に置く2021年12月02日 21時47分

この記事は HTML アドベントカレンダーの 2 日目の分です。


HTML のフォームコントロール要素 (input 要素、textarea 要素、select 要素、button 要素など) は、基本的にはその要素の祖先に位置する (その要素を取り囲む) form 要素に紐づいています。しかし、実は祖先にない form 要素に紐づけることもできます。フォームコントロール要素の form 属性の値に、紐づけたい form 要素の ID (id 属性の値) を指定すればよいのです。

この機能を使えば、フォームの一部に別のフォームの送信ボタンを埋め込んだり、

<form id="edit-form" method="post" action="/edit">
  ...
  <p>
    <button type="submit">保存する</button>
    <button type="submit" form="delete-form">削除する</button>
  </p>
</form>
<form id="delete-form" method="post" action="/delete">
</form>

表の行ごとに異なるフォームを配置したりできます。

<table>
  <thead>
    <tr>
      <th>ID</th>
      <th>タイトル</th>
      <th>操作</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>
        1
        <form id="edit-form-1" method="post" action="/edit">
          <input type="hidden" name="id" value="1">
        </form>
      </td>
      <td>
        <input name="title" value="" form="edit-form-1">
      </td>
      <td>
        <button type="submit" form="edit-form-1">保存する</button>
      </td>
    </tr>
    <tr>
      <td>
        2
        <form id="edit-form-2" method="post" action="/edit">
          <input type="hidden" name="id" value="2">
        </form>
      </td>
      <td>
        <input name="title" value="" form="edit-form-2">
      </td>
      <td>
        <button type="submit" form="edit-form-2">保存する</button>
      </td>
    </tr>
    ...
  </tbody>
</table>