フォームデータの検証

This translation is in progress.

データをサーバへ送信する前に、必須のフォームコントロールが記入され、すべてのフォームコントロールが正しい書式で記入されていることを保証することが重要です。このクライアント側フォーム検証validationは、送信されるデータが様々なフォームコントロールで指定されている要件を満たしていることを保証します。この記事では、クライアント側フォーム検証の基本概念と例を紹介します。

クライアント側検証は最初のチェックであり、ユーザーの使い勝手を良くするために重要な機能です。無効なデータがサーバーに送られて拒否される前に捕らえて修正を要求することで、サーバー側検証のためにサーバーへの往復によって時間を浪費することを防ぎます。サーバー側検証も、サーバーへ送信されたデータをチェックし、不正または悪意のあるデータを確実に拒否するためになお必要です。サーバー側検証はこのガイドでは説明しません。

このチュートリアルはクライアント側のネイティブおよびスクリプトによる検証を紹介します。何が可能か、何が必要かを概観するだけです。このチュートリアルよりも詳しい情報は、制約検証ガイドを参照してください。

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

フォーム検証とは何か

有名なサイトの登録フォームに行き、データを求められている書式で入力しなかいと、フィードバックがあることに気づくでしょう。次のようなメッセージが表示されます。

  • 「このフィールドは必須です」 (このフィールドが空欄にできない場合)
  • 「電話番号は XXX-XXXX の形式で入力してください」 (フォームが3桁の番号の後にダッシュがあり、その後に4桁の番号があるパターンを強制する場合)
  • 「有効なメールアドレスを入力してください」 (入力が適切な、 "somebody@example.com" の形ではない場合)
  • 「パスワードは8文字から30文字の間で、1文字以上の大文字、記号、数字を含む必要があります。」 (長さが minlength 属性よりも短いか、maxlength 属性よりも長いか、内部の pattern 属性または JavaScript で行われる正規表現に一致しない場合)

これはフォーム検証と呼ばれます。データを入力したとき、ブラウザー、またはウェブアプリケーションは、そのデータが正しい書式であり、様々な検証に関する属性によって設定された制約に合っているかをチェックします。情報が正しい書式であれば、ユーザーエージェント (およびアプリケーション) はデータをサーバーに送信することができ、 (ふつうは) データベースに保存されます。正しい書式でなければ、何を修正する必要があるかを説明するメッセージを表示します。

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

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

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

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

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

For good user experience and security, developers should use a combination of both client-side and server-side validation. Client-side validation is more user-friendly than server-side validation because it provides errors during form completion rather than requiring the entire form to be completed, submitted, analyzed, and returned. Server-side validation should be considered required because client-side error checking can be bypassed and network requests can be altered.

内蔵フォーム検証の利用

One of the features of HTML5 form controls is the ability to validate most user data without relying on scripts. This is done by using validation attributes on form elements. Validation attributes allow you to specify rules for a form input, such as whether a value must be filled in (the required attribute); the minimum and maximum length of the data (the minlength and maxlength attributes); the minimum and maximum values (the min and max attributes); whether the data needs to be a number, an email address, or something else (the type attribute); and a regular expression pattern that the data must match (the pattern attribute). In supporting browsers, if the entered data follows all of the specified rules, it is considered valid; if not, it is considered invalid.

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

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

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

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

There are several errors that will prevent the form from being submitted, including a badInput, a patternMismatch, a rangeOverflow or underFlow, a stepMismatch, a form control that is tooLong or tooShort, a typeMismatch, and valueMissing that is required, and even just having a customError,

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

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

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

<form>
  <label for="choose">Would you prefer a banana or cherry?</label>
  <input id="choose" name="i_like">
  <button>Submit</button>
</form>
input:invalid {
  border: 2px dashed red;
}

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

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

required 属性

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

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

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

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

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

input:invalid:required {
  background-image: linear-gradient(to right, pink, lightgreen);
}

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

This CSS causes the input to have a red dashed border when it is invalid and a more subtle solid black border when valid. We also added a background gradient when required and invalid to demonstrate the :required pseudo-class. Try out the new behavior in the example below.

The presence of the required attribute on any element that supports this attribute means the element matches the :required pseudoclass whether it has a value or not. If the <input> has no value, the input will match the :invalid pseudoclass, and the element.validity.valueMissing will return true during constraint validation.

Note: For good user experience, indicate to the user when form fields are required. It isn't only good user experience, it is required by WCAG accessibility guidelines. Also, only require users to input data you actually need: For example, why do you really need to know someone's gender or title?

Try submitting the form without a value. Note how the invalid input gets focus, a default error message ("Please fill out this field") appears, and the form is prevented from being sent.

正規表現での検証

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

Regexs are quite complex, and we don't intend to teach you them exhaustively in this article. Below are some examples to give you a basic idea of how they work.

  • aa の1文字に一致する (baa などではない)。
  • abca と、その次の b と、その次の c に一致する。
  • ab?c—Matches a, optionally followed by a single b, followed by c. ( ac or abc)
  • ab*c—Matches a, optionally followed by any number of bs, followed by c. ( ac , abc, abbbbbc, and so on).
  • a|b — Matches one character that is a or b.
  • abc|xyz — Matches exactly abc or exactly xyz (but not abcxyz or a or y, and so on).
  • There are many more possibilities that we don't need to cover here.

Let's implement an example. Update your HTML to add a pattern attribute like this:

<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:invalid {
  border: 2px dashed red;
}

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

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

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

If a non-empty value of the <input> doesn't match the regular expression's pattern, the input will match the :invalid pseudoclass, and the theInput.validity.patternMismatch will return true when the form is submitted.

The patternMismatch returns true if the element's value doesn't match the provided pattern; false otherwise. When true, the form will be prevented from being submitted in supporting browsers.

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

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

入力欄の長さの制約

You can constrain the character length of all text fields created by <input> or <textarea> by using the minlength and maxlength attributes. A field is invalid - (tooShort) - if it has a value and that value has fewer characters than the minlength value or longer than the maxlengthvalue - (tooLong).

Browsers often don't let the user type a longer value than expected into text fields. A better user experience to maxlength - to not being allowed to enter more than a limited number of characters - is to allow the user to enter text, providing character count feedback in an accessible manner and letting them edit their content down to size. An example of this is the character limit when Tweeting. JavaScript, including solutions using maxlength, can be used.

入力欄の値に制約を加える

For number fields (i.e. <input type="number">), the min and max attributes also provide a validation constraint. If the field's value is lower than the min attribute the rangeUnderflow returns true. If higher than the max attribute, rangeOverflow returns true. Either way, the field will be invalid.

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

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

<form>
  <div>
    <label for="choose">Would you prefer a banana or a cherry?</label>
    <input type="text" 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>
  • Here you'll see that we've given the text field a minlength and maxlength of six, which is the same length as banana and cherry. Entering fewer characters will show as invalid and element.validity.tooShort will return true upon constraint validation. Entering more characters is not possible in most browsers, but element.validity.tooLong would return true.
  • We've also given the number field a min of one and a max of ten. Entered numbers outside this range will show as invalid; users won't be able to use the increment/decrement arrows to move the value outside of this range. If the user manually enters a number outside of this range, constraint validation will return true for either element.validity.rangeUnderflow or element.validity.rangeOverflow. The step attribute defaults to 1, meaning floats, like 3.2, will also show as invalid, returning true for stepMismatch during constraint validation. The number is not required, so removing the value is valid; neither a stepMismatch nor a rangeUnderflow
input:invalid {
  border: 2px dashed red;
}

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

div {
  margin-bottom: 10px;
}

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

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

サンプル全体

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

<form>
  <p>
    <fieldset>
      <legend>Do you have a driver's license?<abbr title="This field is mandatory" aria-label="required">*</abbr></legend>
      <input type="radio" required name="driver" id="r1" value="yes"><label for="r1">Yes</label>
      <input type="radio" required name="driver" id="r2" value="no"><label for="r2">No</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" aria-label="required">*</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 address?</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>
form {
  font: 1em sans-serif;
  max-width: 320px;
}

p > label {
  display: block;
}

input[type="text"],
input[type="email"],
input[type="number"],
textarea,
fieldset {
  width : 100%;
  border: 1px solid #333;
  box-sizing: border-box;
}

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

input:focus:invalid {
  box-shadow: 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() メソッドを呼び出します。

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

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

Note: if you set a custom validity message you must set the custom validity message to the empty string when the value is valid or the form will never be submitted.

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

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

HTML5 の制約検証 API

多くのブラウザーが制約検証 API に対応しています。この API は各フォーム要素で使用できる一連のメソッドやプロパティで構成されています。

制約検証 API のプロパティ

プロパティ 説明
validationMessage コントロールが合格していない制約検証 (もしあれば) を説明するローカライズ済みのメッセージです。またはコントロールが制約の検証の対象ではない場合 (willValidatefalse) または要素の値が制約に合格している場合は空文字列です。
validity 要素の検証状態を説明する ValidityState オブジェクトです。取りうる検証状態の詳細は記事を参照してください。
willValidate フォームが送信されるときに要素が検証される場合に true を返します。そうでない場合は false を返します。

制約検証 API のメソッド

メソッド 説明
checkValidity() 要素の値で妥当性の問題がない場合に true を返します。そうでない場合は false を返します。要素が不正である場合、このメソッドは要素で invalid イベントを発生させます。
HTMLFormElement.reportValidity() この要素の子コントロールが検証の制約を満足するのであれば 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%;

  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;
 
  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%;

  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;
  box-sizing: border-box;
}

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

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

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

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

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

// 多くの古いブラウザーは addEventListener メソッドをサポートしていません。
// 以下はこれを扱うためのシンプルな方法です。なお唯一の方法ではありません。
function addEvent(element, event, callback) {
  let previousEventCallBack = element["on"+event];
  element["on"+event] = function (e) {
    const 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 () {
  // ここで、フィールドが空かを確認しています (フィールドは必須入力ではありません)
  // 空でなければ、内容部が適切な電子メールアドレスかを確認します。
  const test = email.value.length === 0 || emailRegExp.test(email.value);

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

// ユーザーがフィールドに入力したときに、何をするかを定義します。
addEvent(email, "input", function () {
  const 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 () {
  const 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 を必要としませんが、ユーザーについては注意深く考えることが必要です。ユーザーが正しいデータを入力できるよう支援することを、常に忘れないでください。最後に、以下のことを必ず行ってください。

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

このモジュール内の文書