フォーム検証validationは、送信されたデータがアプリケーションで正しく動作するかを確認することで、ユーザーに正しい書式でフォームを埋めてもらうのに役立ちます。この記事では、フォーム検証について知っておくべきことを紹介します。

前提知識: コンピューターリテラシー、適度な HTMLCSSJavaScript の理解。
目的: フォーム検証とは何か、なぜ重要なのか、どのように実装するのかを理解すること。

フォーム検証とは何か

有名なサイトの登録フォームに行ってみると、指定された形式でデータを入力していない場合に、次のようなメッセージが表示されるでしょう。

  • 「このフィールドは必須です」 (このフィールドが空欄にできない場合)
  • 「電話番号は XXX-XXXX の形式で入力してください」 (3桁の番号の後にダッシュがあり、その後に4桁の番号で入力が必要な場合)
  • 「有効なメールアドレスを入力してください」 (入力が "somebody@example.com" の形ではない場合)
  • 「パスワードは8文字から30文字の間で、1文字以上の大文字、記号、数字を含む必要があります。」

これはフォーム検証と呼ばれます。 — データを入力するとき、ウェブアプリケーションはそのデータが正しいかどうかをチェックします。正しければ、アプリケーションはサーバーにデータを送信し、 (ふつうは) データベースに保存します。正しくなければ、何を修正する必要があるかを説明するメッセージを表示します。フォーム検証は様々な方法で実装することができます。

私たちはできるだけ簡単にフォームを埋めてもらいたいわけですが、なぜフォームを検証する必要があるのでしょうか?理由は主に三つあります。

  • 正しいデータを正しい形式で入力してほしい — ユーザーのデータが誤った形式で格納されたり、ユーザーが正しい情報を入力しなかったり、省略したりすると、アプリケーションが正しく動作しないからです。
  • ユーザーのアカウントを保護したい — ユーザーに安全なパスワードを入力させることで、アカウント情報を保護しやすくなります。
  • 自分たちを守りたい — 悪意のあるユーザーが保護のないフォームを悪用して、そのフォームを一部に持つアプリケーションに危害を加える方法がたくさんあります。(ウェブサイトセキュリティを参照してください)。

様々な種類のフォーム検証

ウェブで見かけるフォーム検証には二つの種類があります。

  • クライアント側検証は、データがサーバーへ送信される前にブラウザー内で行われる検証です。これはすぐに反応を返せるので、サーバー側の検証よりもユーザーに親切です。これはさらに分類できます。
    • JavaScript 検証は JavaScript を使ってコーディングされるものです。これは完全にカスタマイズ可能です。
    • 内蔵フォーム検証は、 HTML5 のフォーム検証機能を使用します。これは一般に JavaScript を必要としません。内蔵フォーム検証はパフォーマンスは良いのですが、 JavaScript ほどカスタマイズすることはできません。
  • サーバー側検証は、データが送信された後に、サーバー側で行われる検証です。サーバー側のコードは、データベースにデータを保存する前の検証に使用されます。データの検証に失敗すると、クライアントに応答を送り、ユーザーに何が間違っているかを伝えます。サーバー側検証は、フォーム全体が送信されるまでエラーが表示できないので、クライアント側の検証ほどユーザーに親切ではありません。しかし、サーバー側検証は不正なデータに対するアプリケーションの最終防衛線です。主要なサーバー側フレームワークはデータを検証無害化sanitizing (安全化) する機能を持っています。

現実には、開発者はクライアント側検証とサーバー側検証を組み合わせて使う傾向があります。

内蔵フォーム検証の利用

HTML5 の機能のひとつに、スクリプトに頼ることなくほとんどのユーザーデータを検証できる機能があります。これはフォーム関連要素の検証関連属性を使用すれば、値を入力する必要があるかどうか、データの最短と最長の長さ、数値であるかどうか、メールアドレスかどうかなどや、パターンに一致するかどうかなどの規則を指定することができます。入力されたデータがすべて規則に従っていれば妥当とみなされ、そうでなければ不正とみなされます。

要素が妥当な場合は、次のようになります。

  • 要素が CSS の :valid 疑似クラスに一致します。これにより、妥当な要素に特定のスタイルを適用することができます。
  • ユーザーがデータを送信しようとすると、ブラウザーは止めるものが他になければ(JavaScript など)、フォームを送信します。

要素が不正なときは、次のようになります。

  • 要素が CSS の :invalid 疑似クラスに一致します。これにより、不正な要素に特定のスタイルを適用することができます。
  • ユーザーがデータを送信しようとすると、ブラウザーはフォームをブロックしてエラーメッセージを表示します。

入力要素の制約の検証 ― 簡単なものから

この節では、 <input> 要素を検証するために使用することができる幾つかの異なる HTML5 の機能を見てみます。

簡単な例から始めましょう。 ― 好きな果物をバナナかサクランボから選べる入力欄があるとします。単純なテキストの <input> とそれに合わせたラベル、送信の <button> から成ります。ソースコードは GitHub の fruit-start.html で、ライブサンプルは次の通りです。

始めるにあたって、ハードディスク内の新しいディレクトリに fruit-start.html のコピーを作成してください。

required 属性

required 属性は、使うのがもっとも簡単な HTML5 の検証機能です。 ― 入力欄を必須にしたい場合は、この属性を使用して要素をマークすることができます。この属性が設定されていると、入力欄が空欄の(入力欄は不正だと扱われる)場合はフォームが送信されません(そして、エラーメッセージが表示されるでしょう)。

以下のように、 required 属性を入力欄に追加しましょう。

<form>
  <label for="choose">Would you prefer a banana or cherry?</label>
  <input id="choose" name="i_like" required>
  <button>Submit</button>
</form>

このサンプルファイルの中に含まれている CSS も書いておきましょう。

input:invalid {
  border: 2px dashed red;
}

input:valid {
  border: 2px solid black;
}

これで、入力欄が不正な時、明るい赤の破線の境界線が表示され、妥当な場合はもっと細い黒の境界線が表示されます。以下の例で新しい動作を確認しましょう。

正規表現での検証

もう一つとてもよく使われる機能は pattern 属性で、値として正規表現を取ります。正規表現(regex)はテキスト文字列の中の文字の組み合わせに一致させるために使うことができ、フォームの検証には理想的です(JavaScript と同様に様々な利用ができます)。正規表現はとても複雑であり、この記事では包括的な説明をしようとはしていません。

以下のものはどのように動作するかを基本的な考えを示す例です。

  • a — a の1文字に一致する(b や aa などではない)。
  • abca と、その次の b と、その次の c に一致する。
  • a* — 0文字以上の a に一致する(+ は1文字以上の文字に一致する)。
  • [^a] — a ではない1文字に一致する。
  • a|b — a または b の1文字に一致する。
  • [abc] — a、 b、 c のうち1文字に一致する。
  • [^abc] — a、 b、 c ではない1文字に一致する。
  • [a-z] — 小文字のみの a–z のいずれかの文字に一致します(大文字と小文字を使うには [A-Za-z]、 大文字のみであれば [A-Z])。
  • a.c — a と、その次の任意の1文字と、その次の c に一致する。
  • a{5} — 5文字の a に一致する。
  • a{5,7} — 5文字から7文字の a に一致するが、それより大きくても小さくても一致しない。

次のように、数字やその他の文字もこの表現の中に入れることができます。

  • [ -] — 1文字の空白又はダッシュに一致する。
  • [0-9] — 0から9の任意の数字に一致する。

これらを望みに合わせて本当にあらゆる方法で、さまざまな部品を次々と組み合わせて指定することができます。

  • [Ll].*k — 大文字または小文字の L 1文字と、その次に任意の文字が0文字以上と、その次に小文字の k が1文字続くもの。
  • [A-Z][A-Za-z' -]+ — 大文字1文字と、その次に大文字、小文字、ダッシュ、アポストロフィ、空白のいずれかが1文字以上続くもの。これは英語圏の国で都市や町の名前を検証するのに使うことができ、大文字1文字で始まる必要がありますが、それ以外の文字は含みません。例えばイギリスでは、 Manchester, Ashton-under-lyne, Bishop's Stortford などが一致します。
  • [0-9]{3}[ -][0-9]{3}[ -][0-9]{4} ― アメリカの国内電話番号に単純に一致するものです。3桁の数字、その次に空白又はダッシュ1文字、その次に3桁の数字、その次に空白又はダッシュ1文字、その次に4桁の数字が続くものです。実際には一部の人は地域コードを括弧の中に書くので、もっと複雑にしなければならないでしょうが、単純なデモとして動作します。

とにかく、例を実装しましょう。 ― 次のように、 pattern 属性を HTML に追加しましょう。

<form>
  <label for="choose">Would you prefer a banana or a cherry?</label>
  <input id="choose" name="i_like" required pattern="banana|cherry">
  <button>Submit</button>
</form>

この例では、 <input> 要素は "banana" 又は "cherry" という2つの文字列値のうち1つを受け付けます。

この時点で、 pattern 属性の中の値を以前に見たいくつかの例と同じ値に変更してみて、入力欄が有効になるように入力する値がどのように影響するかを確認してください。自分で考えた値も書いてみて、どのようになるか確認しましょう。果物に関する値を可能にすれば、例分かりやすくなります。

メモ: <input> 要素の型によっては、検証のために pattern 属性が必要ないことがあります。例えば email 型を指定すると、入力された文字列を、妥当な形式のメールアドレス(または、 multiple 属性がある場合はコンマで区切られたメールアドレスのリスト)であることを確認する正規表現で検証します。他の例として、 url 型の入力欄は自動的に正しい形式の URL を要求します。

メモ: <textarea> 要素は pattern 属性に対応していません。

入力欄の長さの制約

<input> 又は <textarea> で作成されるテキストフィールドはすべて、 minlength 及び maxlength 属性を使用して長さの制約を設けることができます。値が minlength の値よりも短かったり、 maxlength の値よりも長かったりする場合は、フィールドは無効です。ブラウザーはどのような場合もユーザーに、テキストフィールドに指定より長い値を入力させませんが、これはきめ細かい制御を行うのに便利です。

数値入力欄(つまり <input type="number">)では、 min 及び max 属性も制約の検証を行います。入力欄の値が min 属性よりも小さかったり、 max 属性よりも大きかったりすると、入力欄は無効になります。

他の例を見てみましょう。 fruit-start.html ファイルの新しいコピーを作成してください。

では、 <body> 要素の中身を削除して、以下のように置き換えてください。

<form>
  <div>
    <label for="choose">Would you prefer a banana or a cherry?</label>
    <input id="choose" name="i_like" required minlength="6" maxlength="6">
  </div>
  <div>
    <label for="number">How many would you like?</label>
    <input type="number" id="number" name="amount" value="1" min="1" max="10">
  </div>
  <div>
    <button>Submit</button>
  </div>
</form>
  • ここで、 text 入力欄に minlengthmaxlength を6に設定したのが分かるでしょう。 banana 及び cherry と同じ長さです。これ以上少ない文字を入力すると無効と表示され、多くのブラウザーではそれ以上の文字を入力することはできません。
  • number 入力欄には min を1に、 max を10に設定しました。 — この範囲外の数値は無効と表示され、値の増加・減少の矢印も、この範囲外に値を動かすことはできないでしょう。

例をライブで実行してみましょう。

メモ: <input type="number"> (及び range のような他の型)は step 属性を取ることもでき、入力コントロール(数値の増加・減少ボタンなど)を使用するときに上げ下げすることができる値の刻みを設定することができます。

サンプル全体

HTML の内蔵検証機能の使い方を示す例の全体を示します。

<form>
  <p>
    <fieldset>
      <legend>Title<abbr title="この入力欄は必須です">*</abbr></legend>
      <input type="radio" required name="title" id="r1" value="Mr"><label for="r1">Mr.</label>
      <input type="radio" required name="title" id="r2" value="Ms"><label for="r2">Ms.</label>
    </fieldset>
  </p>
  <p>
    <label for="n1">How old are you?</label>
    <!-- pattern 属性は number 型の入力欄を実装していないものの、 pattern
         属性には対応しているブラウザー向けの代替策として動作できます。
         なお、 pattern 属性に対応しているブラウザーでは、 number 型の入力欄
         で使用すると暗黙に失敗します。
         ここでは代替策としての使い方のみです。 -->
    <input type="number" min="12" max="120" step="1" id="n1" name="age"
           pattern="\d+">
  </p>
  <p>
    <label for="t1">What's your favorite fruit?<abbr title="This field is mandatory">*</abbr></label>
    <input type="text" id="t1" name="fruit" list="l1" required
           pattern="[Bb]anana|[Cc]herry|[Aa]pple|[Ss]trawberry|[Ll]emon|[Oo]range">
    <datalist id="l1">
      <option>Banana</option>
      <option>Cherry</option>
      <option>Apple</option>
      <option>Strawberry</option>
      <option>Lemon</option>
      <option>Orange</option>
    </datalist>
  </p>
  <p>
    <label for="t2">What's your e-mail?</label>
    <input type="email" id="t2" name="email">
  </p>
  <p>
    <label for="t3">Leave a short message</label>
    <textarea id="t3" name="msg" maxlength="140" rows="5"></textarea>
  </p>
  <p>
    <button>Submit</button>
  </p>
</form>
body {
  font: 1em sans-serif;
  padding: 0;
  margin : 0;
}

form {
  max-width: 200px;
  margin: 0;
  padding: 0 5px;
}

p > label {
  display: block;
}

input[type=text],
input[type=email],
input[type=number],
textarea,
fieldset {
/* WebKit ベースのブラウザーでフォーム関連要素に 
   正しくスタイルを設定するために必要 */
  -webkit-appearance: none;
  
  width : 100%;
  border: 1px solid #333;
  margin: 0;
  
  font-family: inherit;
  font-size: 90%;
  
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

input:invalid {
  box-shadow: 0 0 5px 1px red;
}

input:focus:invalid {
  outline: none;
}

独自のエラーメッセージ

上記の例で見てきたように、ユーザーが不正なフォームを送信しようとするたびにブラウザーはエラーメッセージを表示します。このメッセージを表示する方法は、ブラウザーにより異なります。

これらの自動のメッセージには、2つの欠点があります。

  • CSS でメッセージの表示方法を変更するための標準的な方法がありません。
  • メッセージはブラウザーのロケールに依存しており、ある言語のページでエラーメッセージが別の言語で表示されることがあります。
フランス語版のブラウザーで英語のページを表示する
ブラウザー 表示
Firefox 17 (Windows 7) 英語ページでフランス語のエラーメッセージを Firefox で表示した例
Chrome 22 (Windows 7) 英語ページでフランス語のエラーメッセージを Chrome で表示した例
Opera 12.10 (Mac OSX) 英語ページでフランス語のエラーメッセージを Opera で表示した例

これらのメッセージの外見やテキストを変更するには、 JavaScript を使用しなければなりません。 HTML や CSS だけで変更する方法はありません。

HTML5 では、フォーム要素の状態を確認したりカスタマイズしたりするための制約検証 API を提供します。特に、エラーメッセージのテキストを変更できます。簡単な例を見てみましょう:

<form>
  <label for="mail">I would like you to provide me an e-mail</label>
  <input type="email" id="mail" name="mail">
  <button>Submit</button>
</form>

JavaScript で setCustomValidity() メソッドを呼び出します。

var email = document.getElementById("mail");

email.addEventListener("input", function (event) {
  if (email.validity.typeMismatch) {
    email.setCustomValidity("I expect an e-mail, darling!");
  } else {
    email.setCustomValidity("");
  }
});

JavaScript を使用したフォーム検証

内蔵のエラーメッセージを見かけを制御したい場合や、HTML5 のフォーム検証に対応していないブラウザーに対処したい場合は、 JavaScript を使用する必要があります。

HTML5 の制約検証 API

制約検証 API に対応するブラウザーは増えてきており、当てにできるようになってきました。この API は各フォーム要素で使用できる一連のメソッドやプロパティで構成されています。

制約検証 API のプロパティ

プロパティ 説明
validationMessage コントロールが合格していない制約検証(もしあれば)を説明するローカライズ済みのメッセージです。またはコントロールが制約の検証の対象ではない場合(willValidatefalse)または要素の値が制約に合格している場合は空文字列です。
validity 要素の検証状態を説明する ValidityState オブジェクトです。
validity.customError 要素が独自エラー状態である場合に true を返します。そうでない場合は false を返します。
validity.patternMismatch 要素の値が与えられたパターンに一致しない場合に true を返します。そうでない場合は false を返します。

これが true を返す場合、要素は CSS の :invalid 疑似クラスに一致するでしょう。
validity.rangeOverflow 要素の値が与えられた最大値を超える場合に true を返します。そうでない場合は false を返します。

これが true を返す場合、要素は CSS の :invalid 疑似クラスおよび :out-of-range 疑似クラスに一致するでしょう。
validity.rangeUnderflow 要素の値が与えられた最小値を下回る場合に true を返します。そうでない場合は false を返します。

これが true を返す場合、要素は CSS の :invalid 疑似クラスおよび :out-of-range 疑似クラスに一致するでしょう。
validity.stepMismatch 要素の値が step 属性で与えられた規則に合わない場合に true を返します。そうでない場合は false を返します。

これが true を返す場合、要素は CSS の :invalid 疑似クラスおよび :out-of-range 疑似クラスに一致するでしょう。
validity.tooLong 要素の値が与えられた長さより長い場合に true を返します。そうでない場合は false を返します。

これが true を返す場合、要素は CSS の :invalid 疑似クラスおよび :out-of-range 疑似クラスに一致するでしょう。
validity.typeMismatch 要素の値の構文が正しくない場合に true を返します。そうでない場合は false を返します。

これが true を返す場合、要素は CSS の :invalid 疑似クラスに一致するでしょう。
validity.valid 要素の値の検証に問題がない場合に true を返します。そうでない場合は false を返します。

これが true を返す場合、要素は CSS の :valid 疑似クラスに一致するでしょう。そうでない場合は CSS の :invalid 疑似クラスに一致するでしょう。
validity.valueMissing 要素が入力必須のフィールドであるのに値がない場合に true を返します。そうでない場合は false を返します。

これが true を返す場合、要素は CSS の :invalid 疑似クラスに一致するでしょう。
willValidate フォームが送信されるときに要素が検証される場合に true を返します。そうでない場合は false を返します。

制約検証 API のメソッド

メソッド 説明
checkValidity() 要素の値で妥当性の問題がない場合に true を返します。そうでない場合は false を返します。要素が不正である場合、このメソッドは要素で invalid イベントを発生させます。
setCustomValidity(message) 要素に独自のエラーメッセージを追加します。独自のエラーメッセージを設定すると、要素が不正であるとみなされる場合に指定したエラーが表示されます。これにより JavaScript で、標準の制約検証 API で提供されるもの以外の検証不合格状態を作り出すことができます。ユーザーに問題を報告する際に、メッセージが表示されます。

引数が空文字列である場合は、独自のエラーがクリアされます。

古いブラウザー向けには、制約検証 API に対応していないことを補うための Hyperform などのポリフィルを使用できます。すでに JavaScript を使用していますので、ポリフィルを使用することがウェブサイトやウェブアプリケーションの設計や実装での追加の負担にはなりません。

制約検証 API の使用例

独自のエラーメッセージを作成するために API を使用する方法を見ていきましょう。始めに、HTML です。

<form novalidate>
  <p>
    <label for="mail">
      <span>Please enter an email address:</span>
      <input type="email" id="mail" name="mail">
      <span class="error" aria-live="polite"></span>
    </label>
  </p>
  <button>Submit</button>
</form>

このサンプルフォームでは、ブラウザーの自動検証を無効にするために novalidate 属性を使用しています。これで、検証を制御するためにスクリプトを使用できます。ただし、これは制約検証 API の対応や CSS の疑似クラス :valid:invalid:in-range:out-of-range の適用を無効にするわけではありません。つまり、データを送信する前にブラウザーが自動的なフォームの妥当性確認を行わないとしても、あなた自身で確認を行って、フォームの状態に応じたスタイル設定ができます。

aria-live 属性は、スクリーンリーダーのような支援技術を使用している人々を含む皆に、独自のエラーメッセージを提示するようにします。

CSS

この CSS はフォームへのスタイル設定と、エラー出力をより目立つようにします。

/* これはサンプルの見栄えをよくするスタイルです */
body {
  font: 1em sans-serif;
  padding: 0;
  margin : 0;
}

form {
  max-width: 200px;
}

p * {
  display: block;
}

input[type=email]{
  -webkit-appearance: none;

  width: 100%;
  border: 1px solid #333;
  margin: 0;

  font-family: inherit;
  font-size: 90%;

  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

/* これは不正なフィールド向けのスタイルです */
input:invalid{
  border-color: #900;
  background-color: #FDD;
}

input:focus:invalid {
  outline: none;
}

/* これはエラーメッセージ向けのスタイルです */
.error {
  width  : 100%;
  padding: 0;
 
  font-size: 80%;
  color: white;
  background-color: #900;
  border-radius: 0 0 5px 5px;
 
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

.error.active {
  padding: 0.3em;
}
JavaScript

以下の JavaScript コードは独自のエラー検証を制御します。

// DOM ノードの選択法はたくさんあります。ここではフォーム自体、メールアドレス
// 入力ボックス、そしてエラーメッセージを配置する span 要素を取得しています。

var form  = document.getElementsByTagName('form')[0];
var email = document.getElementById('mail');
var error = document.querySelector('.error');

email.addEventListener("input", function (event) {
  // ユーザーが何かを入力するたびに、メールアドレスのフィールドが妥当かを
  // 確認します。
  if (email.validity.valid) {
    // エラーメッセージを表示している場合に、フィールドが妥当になれば
    // エラーメッセージを取り除きます。
    error.innerHTML = ""; // メッセージの内容物をリセットします
    error.className = "error"; // メッセージの表示状態をリセットします
  }
}, false);
form.addEventListener("submit", function (event) {
  // ユーザーがデータを送信しようとするたびに、メールアドレスの
  // フィールドが妥当かをチェックします。
  if (!email.validity.valid) {
    
    // フィールドが妥当ではない場合、独自のエラーメッセージを
    // 表示します。
    error.innerHTML = "I expect an e-mail, darling!";
    error.className = "error active";
    // また、イベントをキャンセルしてフォームの送信を止めます。
    event.preventDefault();
  }
}, false);

こちらが実際の結果です。

制約検証 API はフォーム検証を制御するための強力なツールであり、HTML および CSS のみで検証を行うよりもはるかにユーザーインターフェイスをコントロールできます。

組み込み API を使用しないフォーム検証

古いブラウザーやカスタムウィジェットにおいて、制約検証 API を使用できない (または使用したくない)ことがあるでしょう。このような場合でも、フォームを検証するために JavaScript が使用できます。フォームを検証には、実際のデータの検証よりもユーザーインターフェイスの疑問が多くなります。

フォームを検証するために、あなたはいくつかの疑問を考えなければなりません。

どのような検証を実施するべきか
どのようにデータを検証するかを決めなければなりません。文字列演算、型変換、正規表現など。これはあなた次第です。フォームのデータは常にテキストであり、スクリプトには常に文字列として渡されることを忘れないようにしてください。
フォームが妥当でない場合に何をするべきか
これは明らかにユーザーインターフェイスの問題です。フォームがどのように動作するかを決めなければなりません。どのような場合でもフォームのデータを送信しますか?エラー状態の入力欄を強調しますか?エラーメッセージを表示しますか?
ユーザーが不正なデータを修正することをどのように支援できるか
ユーザーの不満を軽減するためには、ユーザーに入力内容の修正を案内するために、できるだけ多くの役立つ情報を提供することがとても重要です。明確なエラーメッセージはもちろん、ユーザーが何を求められているか理解できるように前向きの提案をするべきです。

フォーム検証のユーザーインターフェイスの要件について深く学びたいのであれば、ぜひ読むべきである有用な記事があります。

制約検証 API を使用しない例

これまでのことを説明するため、古いブラウザーでも動作するように前出のサンプルを作り直してみましょう。

<form>
  <p>
    <label for="mail">
        <span>Please enter an email address:</span>
        <input type="text" class="mail" id="mail" name="mail">
        <span class="error" aria-live="polite"></span>
    </label>
  <p>
  <!-- 一部の古いブラウザーでは button 要素で、 type 属性に明示的に
       submit を設定する必要があります。 -->
  <button type="submit">Submit</button>
</form>

ご覧の通り、 HTML はほとんど同じであり、 HTML5 の部分を取り除いただけです。ARIA は特に HTML5 との関係はない独立した仕様ですので、ここでは残されています。

CSS

同様に、CSS も大きく変更する必要はありません。:invalid 疑似クラスから実クラスへの変更と、Internet Explorer 6 で動作しない属性セレクターの使用を避けただけです。

/* これはサンプルの見栄えをよくするスタイルです */
body {
  font: 1em sans-serif;
  padding: 0;
  margin : 0;
}

form {
  max-width: 200px;
}

p * {
  display: block;
}

input.mail {
  -webkit-appearance: none;

  width: 100%;
  border: 1px solid #333;
  margin: 0;

  font-family: inherit;
  font-size: 90%;

  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

/* これは不正なフィールド向けのスタイルです */
input.invalid{
  border-color: #900;
  background-color: #FDD;
}

input:focus.invalid {
  outline: none;
}

/* これはエラーメッセージ向けのスタイルです */
.error {
  width  : 100%;
  padding: 0;
 
  font-size: 80%;
  color: white;
  background-color: #900;
  border-radius: 0 0 5px 5px;
 
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

.error.active {
  padding: 0.3em;
}
JavaScript

JavaScript コードでは大きな変更があり、多くの面倒な作業が必要です。

// 古いブラウザーで DOM ノードを選択する方法は少ない
var form  = document.getElementsByTagName('form')[0];
var email = document.getElementById('mail');

// 以下は DOM 内で次の兄弟要素にたどり着くための技です。
// これは容易に無限ループになることがあるため、危険です。
// 新しいブラウザーでは、element.nextElementSibling を使用しましょう。
var error = email;
while ((error = error.nextSibling).nodeType != 1);

// HTML5 仕様書より
var emailRegExp = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;

// 多くの古いブラウザーは addEventListener メソッドをサポートしていません。
// 以下はこれを扱うためのシンプルな方法です。なお唯一の方法ではありません。
function addEvent(element, event, callback) {
  var previousEventCallBack = element["on"+event];
  element["on"+event] = function (e) {
    var output = callback(e);

    // `false` を返すコールバックはコールバックチェーンを止めて、
    // イベントコールバックの実行を中断します。
    if (output === false) return false;

    if (typeof previousEventCallBack === 'function') {
      output = previousEventCallBack(e);
      if(output === false) return false;
    }
  }
};

// ここから検証制約の再構築ができます。
// CSS の疑似クラスに頼ることはできないため、メールアドレスフィールドで  
// valid/invalid クラスを明示的に設定しなければなりません。
addEvent(window, "load", function () {
  // ここで、フィールドが空かを確認しています (フィールドは必須入力ではありません)
  // 空でなければ、内容部が適切な電子メールアドレスかを確認します。
  var test = email.value.length === 0 || emailRegExp.test(email.value);

  email.className = test ? "valid" : "invalid";
});

// ユーザーがフィールドに入力したときに、何をするかを定義します。
addEvent(email, "keyup", function () {
  var test = email.value.length === 0 || emailRegExp.test(email.value);
  if (test) {
    email.className = "valid";
    error.innerHTML = "";
    error.className = "error";
  } else {
    email.className = "invalid";
  }
});

// ユーザーがデータを送信しようとしたときに何をするかを定義します。
addEvent(form, "submit", function () {
  var test = email.value.length === 0 || emailRegExp.test(email.value);

  if (!test) {
    email.className = "invalid";
    error.innerHTML = "I expect an e-mail, darling!";
    error.className = "error active";

    // 一部の古いブラウザーは event.reventDefault() メソッドをサポートしていません。
    return false;
  } else {
    email.className = "valid";
    error.innerHTML = "";
    error.className = "error";
  }
});

結果は以下のようになります。

ご覧の通り、自分でで検証システムを構築するのは大変なことではありません。難しいのはクロスプラットフォームで、かつ作成するであろうあらゆるフォームで使用できる汎用的なものにすることです。フォーム検証を行うために利用できる、多くのライブラリがあります。使用するのをためらうべきではありません。いくつか例を挙げます。

リモート検証

場合によっては、リモートで検証を実行することが有用かもしれません。この種の検証は、ユーザーが入力したデータをアプリケーションのサーバー側で保存している追加データに結び付ける際に必要になります。この利用例として、登録フォームでユーザー名を尋ねるときです。重複を避けるためには、ユーザーにデータを送信させてから、エラーを伴ったフォームを送り返すよりも、ユーザー名が利用できるかをチェックするために AJAX リクエストを実行する方がスマートです。

このような検証を実施するには、いくつか注意すべきことがあります。

  • API や一部のデータを広く公開することになります。微妙なデータでないことを確認してください。
  • ネットワークの遅延があるので、検証は非同期で行うことになります。検証が正しく行われなくてもユーザーはブロックされないので、正しいことを確認するために UI でいくらかの作業が必要になります。

まとめ

フォーム検証は複雑な JavaScript を必要としませんが、ユーザーについては注意深く考えることが必要です。ユーザーが正しいデータを入力できるよう支援することを、常に忘れないでください。最後に、以下のことを必ず行ってください。

  • 明確なエラーメッセージを表示してください。
  • 入力形式については寛容になってください。
  • どこでエラーが発生しているかを正確に示してください(特に大きなフォームで)。

このモジュール内の文書

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

このページの貢献者: mfuji09, Uemmra3, chrisdavidmills, yyss, ethertank
最終更新者: mfuji09,