<form> と <form action="">

公開日

Webシステムでフォーム送信を行う際、送信先URLを <form> 要素の action 属性に指定しますが、特定のケースではその記述を省略することができます。また、その記法は時代によって変わっており、ブラウザの対応度合いなど注意すべき点があります。

HTML4 / XHTML1 の <form action="">

HTML4 / XHTML1 の時代、<form> 要素(www.w3.org)の action 属性の定義は

  • action 属性は必須(#REQUIRED)
  • action 属性値は %URI;

でした。これはすなわち action 属性を省略できない[1]一方、 action 属性値を空にする <form action=""> は正当であることを意味します。 HTML4 の仕様書では %URI; の詳細はRFC 2396(tools.ietf.org)を参照せよとあり、そこの 4.2 節「Same-document References」ではこのように書かれています。

A URI reference that does not contain a URI is a reference to the current document. In other words, an empty URI reference within a document is interpreted as a reference to the start of that document, and a reference containing only a fragment identifier is a reference to the identified fragment of that document. Traversal of such a reference should not result in an additional retrieval action. However, if the URI reference occurs in a context that is always intended to result in a new request, as in the case of HTML's FORM element, then an empty URI reference represents the base URI of the current document and should be replaced by that URI when transformed into a request.

4.2. Same-document References (RFC 2396)(tools.ietf.org)

RFC 2396 は2005年1月にはRFC 3986(tools.ietf.org)によって置き換えられ、記述も少し変わっています。

When a URI reference refers to a URI that is, aside from its fragment component (if any), identical to the base URI (Section 5.1), that reference is called a "same-document" reference. The most frequent examples of same-document references are relative references that are empty or include only the number sign ("#") separator followed by a fragment identifier.

4.4. Same-Document Reference (RFC 3986)(tools.ietf.org)

すなわち <form action=""> とした場合、通常はその文書自身のURIが送信先となり、 <base> 要素があるときはそこで指定された基本URI(Base URI)となることになります[2]

属性値が %URI; な要素としては、他に <a href><q cite>, <img src> などがありますが、これらは値を空文字列にすることは滅多にありませんでした。今でこそ <template> 要素の登場で、描画前の状態として値が空の属性を記述することはありますが、当時はそんな技術はなかったので。

一方、 <form action> については、送信フォームで初期画面と送信後画面を同一のURLで受け持つ場合などは、 action 属性値を空文字列にするメリットがありました。

PHPプログラムによる、簡単な登録フォームの例を記します。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<? if (!isset($_POST['regist'])): ?>
  <title>名前入力</title>
  <form action="" method="post">
    <p><label>名前<input name="name"></label></p>
    <p><input type="submit" name="regist" value="登録"></p>
  </form>
<? else: ?>
  <?
    /* ここにサーバー側の登録処理が入る */
  ?>
  <title>登録完了</title>
  <p>登録が完了しました。</p>
<? endif; ?>

このコードでは、コード内にプログラムのファイル名は一切書かれていません。そのため、このプログラムを regist.php で保存しようと、あとで regist-user.php にリネームしようと、コード自体に手を入れる必要はありません。便利ですね。

ブラウザのサポート状況も良好で、PCブラウザは IE 6 や黎明期の Firefox でも問題なく動いていました。ただし、古いガラケーでは動かない端末も一部存在しました。

HTML5 での変化

W3C の HTML5 でも当初は action 属性値に空文字列が認められていました。2011年1月13日版まではこんな記述が書かれていました。

The action and formaction content attributes, if specified, must have a value that is a valid URL potentially surrounded by spaces.

4.10.19.6 Form submission (HTML5 - W3C Working Draft 13 January 2011)(www.w3.org)

これが2011年4月5日版では、以下のように文言が変わり、 action 属性値を空にすることはできなくなりました。

The action and formaction content attributes, if specified, must have a value that is a valid non-empty URL potentially surrounded by spaces.

4.10.19.6 Form submission (HTML5 - W3C Working Draft 05 April 2011)(www.w3.org)

今の HTML Living Standard も同じ記述で、空の値は認められていません。

The action and formaction content attributes, if specified, must have a value that is a valid non-empty URL potentially surrounded by spaces.

4.10.18.6 Form submission (HTML Living Standard — Last Updated 15 April 2020)(html.spec.whatwg.org)

昔は仕様で認められており、実際にそうするメリットもあった空の値がどうしてダメになったのか、その経緯は追っていないので分かりませんが、考える理由として action 属性が必須という制約がなくなり、属性自体を省略した場合は属性値が空の場合と同じ挙動になると定義されているため、 action="" を引き続き認める理由がなくなったのかもしれません。

要するに、それまで <form action=""> と書いていたものは action 属性を削除した <form> に置き換えれば同じ意味を持つことになります。

ブラウザのサポート状況

前述のとおり、サーバーへの送信自体は化石級のガラケーを除きほとんどのブラウザで問題なかったのですが、 JavaScript での取り扱い状況は芳しくなく、 HTMLFormElement.action が正しい値を返さない問題がありました。

<form action=""><!-- あるいは action 属性自体を省略する -->
</form>
<script>
  const formElement = document.forms[0];
  const actionUrl = formElement.action;
  console.log(actionUrl); // 当該ページのURLになるのが正しい
</script>

IE がダメダメなのは想像に難くないと思いますが、モダンブラウザでも実用に耐えるようになったのは比較的最近のことで、例えばFirefox 55 以前は空文字列を返していた(www.fxsitecompat.dev)事象がありますし、 Safari は2020年4月現在でも action 属性なしのパターンに対応していません。

http://localhost/foo/bar で提供されるフォームにおける、 HTMLFormElement.action の取得結果を以下にまとめます。

ブラウザaction=""action 属性なし
Firefox 55✘ 空文字列✘ 空文字列
Firefox 75✔ http://localhost/foo/bar✔ http://localhost/foo/bar
Chrome 81✔ http://localhost/foo/bar✔ http://localhost/foo/bar
iOS 13.4 + Safari✔ http://localhost/foo/bar✘ 空文字列
IE 11✘ http://localhost/foo/✘ 空文字列
Edge 44(EdgeHTML 18)✔ http://localhost/foo/bar✘ 空文字列
Edge 81✔ http://localhost/foo/bar✔ http://localhost/foo/bar

この結果を見ると、 Firefox, Chrome, Edge の最新版は問題ない一方、 Safari や旧 Edge などいくつかのブラウザは action 属性なしのパターンに対応していないことが分かります。

ただし、実際とは違う値が取得されてしまう IE 11 の action="" のパターンはちょっと厄介なものの、それ以外の空文字列を返すブラウザに対しては、 const actionUrl = formElement.action || document.URL; と一工夫加えることで正しい値が取得できますから、大きな問題にはならなそうな気もします。


というわけで、サーバー側プログラムへの送信だけのケース、あるいは JavaScript で HTMLFormElement.action を取得する場合でも今の書き方(action属性値を空にするのではなく属性を省略する)をしたうえで、JSコードに空文字列を返すブラウザへの対策を行えば、 action に URL を指定せずブラウザの自動取得に任せる方法は現実的に可能であると言えます。

もっとも、これは個人的な感覚ではあるのですが、 method="dialog" でもないのに action 属性を省略するのはなんとなく気持ち悪い気がしてしまって……。 HTML4 時代に散々「action 属性は #REQUIRED」と刷り込まれてきた体験から来る感覚なのでしょうか。 HTML4 を書いたことのない人はまた違う感覚だったりするのかな。

  • [1]ちなみに HTML 2.0(RFC1866) や HTML 3.2 では #IMPLIED だったので省略可能でした。
  • [2]実際は多くのブラウザが RFC3986 の記述に反して、 <base> 要素が指定されていても常に文書自身の URL を示す挙動になっていました。