<form>
と <form action="">
Webシステムでフォーム送信を行う際、送信先URLを <form>
要素の action
属性に指定しますが、特定のケースではその記述を省略することができます。また、その記法は時代によって変わっており、ブラウザの対応度合いなど注意すべき点があります。
HTML4 / XHTML1 の <form action="">
HTML4 / XHTML1 の時代、<form>
要素の action
属性の定義は
action
属性は必須(#REQUIRED
)action
属性値は%URI;
でした。これはすなわち action
属性を省略できない[1]一方、 action
属性値を空にする <form action="">
は正当であることを意味します。 HTML4 の仕様書では %URI;
の詳細はRFC 2396(tools.ietf.org
)を参照せよとあり、そこの 4.2 節「Same-document References」ではこのように書かれています。
RFC 2396 は2005年1月には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日版まではこんな記述が書かれていました。
これが2011年4月5日版では、以下のように文言が変わり、 action
属性値を空にすることはできなくなりました。
今の HTML Living Standard も同じ記述で、空の値は認められていません。
昔は仕様で認められており、実際にそうするメリットもあった空の値がどうしてダメになったのか、その経緯は追っていないので分かりませんが、考える理由として 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 を書いたことのない人はまた違う感覚だったりするのかな。