ウェブフォームの作成は常に複雑な作業でした。フォーム自体をマークアップすること自体は簡単ですが、それぞれの入力欄が妥当で一貫しているかどうかをチェックすることはもっと難しく、問題をユーザーに伝えることは頭痛がするかもしれません。 HTML5 では、フォームに新しい仕組みが導入されました。 <input> 要素に意味を持つ新しい型と、クライアント側でフォームの内容をチェックする作業を簡単にする制約の検証が追加されました。基本的な、よくある制約は、 JavaScript を必要とせずに、新しい属性を設定することでチェックできます。もっと複雑な制約は制約の検証 API を使用して検査することができます。

メモ: HTML5 の制約の検証は、サーバー側での検証の必要性をなくす訳ではありません。不正なフォームのリクエストは減少することが期待されるものの、不正なリクエストはまだ互換性のないブラウザー(例えば、 HTML5 や JavaScript に対応していないブラウザー)から送られたり、ウェブアプリケーションをだまそうとする悪意のある人から送られたりする可能性があります。従って、 HTML4 の時と同様、クライアント側で行われている検証と一貫性のある方法で、サーバー側でも入力の制約を検証する必要があります。

内蔵の基本的な制約

HTML5 では、基本的な制約は2通りの方法で定義されます。

  • <input> 要素の type 属性に意味的に最も適切な値を選択することで、例えば email を選択することで、値が妥当なメールアドレスであるかどうかをチェックする制約が自動的に作成されます。
  • 検証関連属性を設定することで、基本的な制約を簡単な方法で、 JavaScript の必要なく記述できます。

意味を持つ入力型

type 属性の内蔵の制約は次の通りです。

入力型 制約の説明 関連付けられた違反
<input type="URL"> 値は絶対 URL でなければなりません。つまり、次の中の1つです。
  • 妥当な URI (RFC 3986 で定義)
  • クエリコンポーネントのない妥当な IRI (RFC 3987 で定義)
  • クエリコンポーネントがあり、エスケープされていない非 ASCII 文字のがない妥当な IRI (RFC 3987 で定義)
  • 妥当な IRI で、文書の文字セットが UTF-8 または UTF-16 のもの(RFC 3987 で定義)
Type mismatch 制約違反
<input type="email"> 値は ABNF 表記で 1*( atext / "." ) "@" ldh-str 1*( "." ldh-str ) に従う必要があります。
  • atextRFC 5322 で定義。つまり、 ASCII 文字 (AZ 及び az)、 数字 (09) 又は特殊文字 ! # $ % & ' * + - / = ? ` { } | ~  の中の1文字。
  • ldh-strRFC 1034 で定義。つまり、 ASCII 文字と、数字及び - が混在したものが単語としてまとめられ、ドット (.) で区切られたもの。
メモ: multiple 属性が設定されている場合、この入力欄には、複数のメールアドレスをコンマ区切りのリストとして設定することができます。ここに書かれている条件を満足しないものがある場合は、 Type mismatch 制約違反が発生します。
Type mismatch 制約違反

なお、ほとんどの入力型には内蔵の制約がありません。制約の検証によって防ぐことができるものや、既定で不正な値を妥当な値に変換する無害化アルゴリズムを持つものがあるからです。

以下の属性が基本的な制約を記述するために使用されます。

属性 属性が対応する入力型 検証値 制約の説明 関連する違反
pattern text, search, url, tel, email, password JavaScript 正規表現ECMAScript 5global, ignoreCase, multiline フラグが無効な状態でコンパイル) 入力値はパターンに一致しなければならない。 Pattern mismatch 制約違反
min range, number 有効な数値 入力値は検証値以上でなければならない。 Underflow 制約違反
date, month, week 有効な日付
datetime, datetime-local, time datetime, datetime-local, time 有効な日時
max range, number 有効な数値 入力値は検証値以下でなければならない Overflow 制約違反
date, month, week 有効な日付
datetime, datetime-local, time 有効な日時
required text, search, url, tel, email, password, date, datetime, datetime-local, month, week, time, number, checkbox, radio, file. <select> 及び <textarea> 要素でも指定可 論理値属性なのでなし。存在すれば means true、存在しなければ false を表す。 (設定されていれば)値がなければならない。 Missing 制約違反
step date 日数の整数値 any の値が設定されていない限り、値は min + step の整数倍でなければならない。 Step mismatch 制約違反
month 月数の整数値
week 週数の整数値
datetime, datetime-local, time 秒数の整数値
range, number 整数
maxlength text, search, url, tel, email, password. <textarea> 要素にも指定可 長さの整数値 文字数がこの属性の値を越えてはならない。 Too long 制約違反

制約の検証のプロセス

制約の検証は単一のフォーム要素と <form> 要素自身であるフォームレベルのどちらかに対して、制約の検証 API を通じて行われます。制約の検証は次の方法で行われます。

  • フォームに関する DOM インターフェイス(HTMLInputElement, HTMLSelectElement, HTMLButtonElement, HTMLTextAreaElement)の checkValidity() メソッドを呼び出すこと。その要素のみの制約を評価し、スクリプトがこの情報を取得できます。(これはふつう、ユーザーエージェントが CSS の疑似クラスの :valid 又は :invalid のどちらを適用するかを判断するときに行います。)
  • HTMLFormElement インターフェイスの checkValidity() 関数を呼び出すこと。これは静的な制約の検証と呼ばれています。
  • フォーム自身を送信しようとすること。これは対話的な制約の検証と呼ばれています。
Note:
  • <form> 要素に novalidate 属性が設定されている場合、対話的な制約の検証は行われません。
  • HTMLFormElement インターフェイスの send() メソッドを呼び出すと、制約の検証を行いません。言い換えれば、このメソッドは制約を満たさなくてもフォームのデータをサーバーに送信します。

HTML5 の制約 API を利用した複雑な制約

JavaScript と制約 API を使用すると、もっと複雑な制約、例えば、複数の入力欄を組み合わせる制約や、複雑な計算による制約を実装できます。

基本的に、(onchange などの)フォーム入力欄の JavaScript を起動して、制約に違反しているかどうかを計算し、 field.setCustomValidity() メソッドを使用して、検証の結果を設定します。空文字列は制約を満たしていることを意味し、他の文字列ならばエラーを表し、文字列はユーザーに表示されるエラーメッセージです。

複数の入力欄を組み合わせた制約: 郵便番号の検証

郵便番号の形式は国によって様々です。大部分の国では任意で国コード(例えばドイツならば D-、フランス又はスイスならば F- )の接頭辞を付けることができますが、国によっては一定の桁数の数値のみです。その他、たとえばイギリスではもっと複雑な構造で、特定の位置に文字を入れることができます。

メモ: これは包括的な郵便番号検証ライブラリではなく、主要概念の説明のためのものです。

例えば、この単純なフォームに制約の検証をチェックするスクリプトを追加してみます。

<form>
    <label for="ZIP">郵便番号 : </label>
    <input type="text" id="ZIP"> 
    <label for="Country">国 : </label>
    <select id="Country">
      <option value="ch">スイス</option>
      <option value="fr">フランス</option>
      <option value="de">ドイツ</option>
      <option value="nl">オランダ</option>
    </select>
    <input type="submit" value="Validate">
</form>

これは以下のように表示されます。

まず、制約自体をチェックする関数を書きましょう。

function checkZIP() {
  // それぞれの国で、従うべき郵便番号のパターンを定義しています
  var constraints = {
    ch : [ '^(CH-)?\\d{4}$', "スイスの郵便番号はちょうど4桁の数字でなければなりません。例: CH-1950 又は 1950" ],
    fr : [ '^(F-)?\\d{5}$' , "フランスの郵便番号はちょうど5桁の数字でなければなりません。例: F-75012 又は 75012" ],
    de : [ '^(D-)?\\d{5}$' , "ドイツの郵便番号はちょうど4桁の数字でなければなりません。例: D-12345 又は 12345" ],
    nl : [ '^(NL-)?\\d{4}\\s*([A-RT-Z][A-Z]|S[BCE-RT-Z])$',
                    "オランダの郵便番号はちょうど4桁の数字と、続く2文字の SA, SD, SS 以外の英字でなければなりません。" ]
  };
  
  // 国の id を読み取る
  var country = document.getElementById("Country").value;

  // 郵便番号の入力欄を取得
  var ZIPField = document.getElementById("ZIP");

  // 制約チェッカーを作成する
  var constraint = new RegExp(constraints[country][0], "");
    console.log(constraint);


  // チェックする
  if (constraint.test(ZIPField.value)) {
    // 郵便番号が制約に従っていれば、 ConstraintAPI でそれを知らせる
    ZIPField.setCustomValidity("");
  }
  else {
    // 郵便番号が制約に従っていなければ、 ConstraintAPI で
    // その国で要求されているメッセージを与える
    ZIPField.setCustomValidity(constraints[country][1]);
  }
}

それから、 <select> onchange イベントと、 <input>oninput イベントにリンクします。

window.onload = function () {
    document.getElementById("Country").onchange = checkZIP;
    document.getElementById("ZIP").oninput = checkZIP;
}

郵便番号の検証のライブサンプルを見ることができます。

アップロード前にファイルのサイズを制限

他にもよくある制約として、アップロードするファイルのサイズの制限があります。ファイルを送信する前にクライアント側でこのチェックを行うには、制約 API と、特に field.setCustomValidity() メソッドにおいて他の JavaScript API である HTML5 File API を組み合わせる必要があります。

HTML の部分は次の通りです。

<label for="FS">75KBより小さいファイルを選択してください : </label>
<input type="file" id="FS">

このように表示されます。

JavaScript が選択されたファイルを読み、 File.size() メソッドでサイズを取得し、それを(ハードコーディングされた)制約と比較して、違反があったらブラウザーに知らせるために制約 API を呼び出します。

function checkFileSize() {
  var FS = document.getElementById("FS");
  var files = FS.files;

  // (少なくとも)1つのファイルが選択されている場合
  if (files.length > 0) {
     if (files[0].size > 75 * 1024) { // 制約をチェック
       FS.setCustomValidity("選択されたファイルは75KBを超えています");
       return;
     }
  }
  // カスタム制約の違反なし
  FS.setCustomValidity("");
}

最後に正しいイベントをメソッドでフックします。

window.onload = function () {
  document.getElementById("FS").onchange = checkFileSize;
}

ファイルサイズの制約の検証のライブサンプルもご覧ください。

制約の検証の視覚的スタイル付け

制約の設定以外に、ウェブ開発者はユーザーに表示されるメッセージやそのスタイルを制御したいものです。

要素の外見の制御

要素の外見は CSS 疑似クラスで制御することができます。

CSS の :required 及び :optional 疑似クラス

:required 及び :optional 疑似クラスで、 required 要素を持つフォーム要素や、持たないフォーム要素に一致するセレクターを書くことができます。

CSS の :-moz-placeholder 疑似クラス

:-moz-placeholder を参照してください。

CSS の :valid 及び :invalid 疑似クラス

:valid 及び :invalid 疑似クラスは、入力型の設定に基づいて中身が検証された、又は検証に失敗した <input> 要素を表します。これらのクラスにより、ユーザーが有効または無効なフォーム要素にスタイル付けして、要素がの中身が正しい形式かどうかを見分けやすくすることができます。

既定のスタイル

制約違反のテキストの制御

x-moz-errormessage 属性

x-moz-errormessage 属性は Mozilla による拡張で、入力欄の検証に失敗したときに表示されるエラーメッセージを指定します。

メモ: この拡張は標準外です。

制約 API の element.setCustomValidity()

element.setCustomValidity(error) メソッドは、フォームが送信されたときに表示されるカスタムエラーメッセージを表示するために使用します。メソッドは文字列引数 error を取ることで動作します。 error が空文字列でない場合は、メソッドは検証が失敗したと見なし、 error をエラーメッセージを表示します。 error が空文字列であれば、要素は検証されたと見なし、エラーメッセージをリセットします。

制約 API の ValidityState オブジェクト

DOM の ValidityState インターフェイスは制約の検証の結果として、要素が入ることができる検証状況を表します。また、正しくない場合は、要素の値の検証に失敗した理由を説明するのに役立ちます。

個人別の整形の例

HTML4 のフォールバック

小技によるフォールバック

JavaScript によるフォールバック

まとめ

ドキュメントのタグと貢献者

 このページの貢献者: mfuji09
 最終更新者: mfuji09,