--- title: クライアント側のフォームデータ検証 slug: Learn/Forms/Form_validation tags: - HTML - Intermediate - JavaScript - Web - ウェブ - ガイド - フォーム - フォーム検証 - 中級者向け - 例 translation_of: Learn/Forms/Form_validation ---
データをサーバーへ送信する前に、必須のフォームコントロールが記入され、すべてのフォームコントロールが正しい書式で記入されていることを保証することが重要です。このクライアント側フォーム検証は、送信されるデータが様々なフォームコントロールで指定されている要件を満たしていることを保証します。この記事では、クライアント側フォーム検証の基本概念と例を紹介します。
前提知識: | コンピューターリテラシー、適度な HTML、CSS、JavaScript の理解。 |
---|---|
目的: | フォーム検証とは何か、なぜ重要なのか、どのように実装するのかを理解すること。 |
クライアント側検証は最初のチェックであり、ユーザーの使い勝手を良くするために重要な機能ですクライアント側で不当なデータを捕捉することで、ユーザーはすぐに修正できます。もしも無効なデータがサーバーに送られてから拒否される場合、サーバーへの往復とクライアント側に戻ってユーザーにデータを修正するように指示することにより、かなり時間を浪費します。
しかし、クライアント側の検証はセキュリティ対策とは考えられません!アプリは常にサーバー側でもクライアント側と同様に送信されたデータのセキュリティをチェックします。なぜならクライアント側の検証は容易に回避することができて、悪意のユーザーは簡単に、サーバーへ不正なデータを送信できます。何が起こり得るかは ウェブサイトセキュリティを見てください。サーバー側検証はこのガイドの範囲を超えますが、覚えておいてください。
有名なサイトの登録フォームに行き、データを求められている書式で入力しないと、フィードバックがあることに気づくでしょう。次のようなメッセージが表示されます。
これはフォーム検証と呼ばれます。データを入力したとき、ブラウザー、またはウェブアプリケーションは、そのデータが正しい書式であり、アプリケーションに設定された制約に合っているかをチェックします。ブラウザーで行われる検証はクライアント側検証と、サーバー側で行われるものはサーバー側検証と呼ばれます。この章では、クライアント側検証に集中します。
情報が正しい書式であれば、アプリケーションはデータのサーバーへの送信を許可し、(ふつうは) データベースに保存されます。正しい書式でなければ、何を修正する必要があるかを説明するメッセージを表示し、ユーザーに再入力させます。
私たちはできるだけ簡単にフォームを埋めてもらいたいわけですが、なぜフォームを検証する必要があるのでしょうか?理由は主に三つあります。
ウェブで見かけるフォーム検証には二つの種類があります。
HTML5 のフォーム制御の機能の一つに JavaScript に頼らない多くのユーザーデータの検証があります。これはフォーム要素の検証の属性を使って行います。これまで多くを見てきましたが、まとめ直すと:
required
: 属性は値が入力されているべきかどうかを指定します。minlength
属性と maxlength
属性: データ長の最小値と最大値を指定します。min
属性と max
属性: 値の最小値と最大値を指定します。type
属性: その入力データが数値や、E メールアドレスや、特定の指定型かを指定します。pattern
属性: データが指定された正規表現にマッチするかどうかを指定します。入力データをこの指定されたルールに基いて検証します。検証にパスすれば妥当で検証にパスしなければ妥当ではないと考えます。
要素が妥当な場合は、次のようになります。
要素が不正なときは、次のようになります。
注: サーバーへの送信を中断するエラーがいくつかあります。次のものが含まれます: {{domxref('validityState.badInput', 'badInput')}}、{{domxref('validityState.patternMismatch','patternMismatch')}}、{{domxref('validityState.rangeOverflow','rangeOverflow')}} または{{domxref('validityState.rangeUnderflow','underFlow')}}、{{domxref('validityState.stepMismatch','stepMismatch')}}、フォームの制御の {{domxref('validityState.tooLong','tooLong')}} または{{domxref('validityState.tooShort','tooShort')}}、{{domxref('validityState.typeMismatch','typeMismatch')}}、と 必要とされた値の{{domxref('validityState.valueMissing','valueMissing')}}、また {{domxref('validityState.customError','customError')}}も含まれる。
この節では、これまで述べてきたいくつかの属性をテストします。
簡単な例から始めましょう。― 好きな果物を banana(バナナ)か cherry(サクランボ)から選べる入力欄があるとします。単純なテキストの {{HTMLElement("input")}} とそれに合わせたラベル、送信の {{htmlelement("button")}} から成ります。ソースコードは GitHub の fruit-start.html で、ライブサンプルは次の通りです。
<form> <label for="choose">banana と cherry のどちらが好き?</label> <input id="choose" name="i_like"> <button>Submit</button> </form>
input:invalid { border: 2px dashed red; } input:valid { border: 2px solid black; }
{{EmbedLiveSample("Simple_start_file", "100%", 80)}}
始めるにあたって、ハードディスク内の新しいディレクトリーに fruit-start.html
のコピーを作成してください。
required
属性は、使うのがもっとも簡単な HTML5 の検証機能です。入力欄を必須にしたい場合は、この属性を使用して要素をマークすることができます。この属性が設定されていて、要素が {{cssxref(':required')}} にマッチすると、UI疑似クラスとフォームは送信されず、入力が空の場合のエラーメッセージが表示されるでしょう。空のままでは、この入力は不正とみなされ、{{cssxref(':invalid')}} 疑似クラスにマッチします。
以下のように、required
属性を入力欄に追加しましょう。
<form> <label for="choose">banana と cherry のどちらが好き? (要入力)</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; }
この CSS によって、入力が妥当でない場合には、入力を赤の破線で境界線を描きますが、入力が妥当な場合には、黒の直線で境界線を描きます。要求された値があり、値が妥当でないときは背景にグラディエーションを追加します。つぎの例の動作を確認しましょう。
{{EmbedLiveSample("The_required_attribute", "100%", 80)}}
注: この例は GitHub の fruit-validation.html で見ることができます (ソースコードも見てください)。
値のないままフォームを送信してみましょう。妥当ではない入力がどのようにフォーカスされるか注意しましょう。デフォルトのエラーメッセージ(「このフィールドは入力必須です。」) が表示され、フォームの送信を阻止します。
required
属性をサポートしている要素にこの属性がある場合、その要素に値があるかないかによって、要素が {{cssxref(':required')}} 疑似クラスに一致するかどうかが決まります。もし {{HTMLElement("input")}} に値がなければ、input
は{{cssxref(':invalid')}} 疑似クラスに一致します。
注意: よりよいユーザーエクスペリエンスのために、フォームのフィールドが必要なときにはユーザーに通知しましょう。これはユーザーエクスペリエンスだけに良いというわけではなく、WCAG アクセシビリティ ガイドラインで求められています。また、あなたが本当に必要とする場合にのみ必須にしましょう。例えばあなたは誰かの性別や肩書などの情報は本当に必要でしょうか?
もう一つとてもよく使われる機能は pattern
属性で、値として正規表現を取ります。正規表現 (regex) はテキスト文字列の中の文字の組み合わせに一致させるために使うことができ、フォームの検証には理想的です (JavaScript と同様に様々な利用ができます) 。
正規表現はかなり複雑です。このモジュールでは正規表現のすべてを説明する意図はありません。いくつかの例を挙げますのでどのように動作するか基本的なアイディアを把握してください。
a
— a
の 1文字に一致する (b
や aa
などではない)。abc
— a
と、その次の b
と、その次の c
の並びに一致する。ab?c
— a
と、その次にひとつだけ b
があるかないかと、その次の c
の並びに一致する ( ac
または abc
)ab*c
— a
と、その次に任意の数の b
が続き、その次に c
のある並びに一致する。( ac
, abc
, abbbbbc
, 等)a|b
— 一文字の a
または b
に一致するabc|xyz
— abc
の並びまたは xyz
の並びに一致する。これは abcxyz
や a
や y
などには一致しない。正規表現には多くの組合せがあるので例はここまでとする。完全な一覧や多くの例は、正規表現ドキュメントを参照してください。
使用例を実装しましょう。HTML を更新して pattern
属性を追加しましょう:
<form> <label for="choose">banana と cherry のどちらが好き?</label> <input id="choose" name="i_like" required pattern="[Bb]anana|[Cc]herry"> <button>Submit</button> </form>
input:invalid { border: 2px dashed red; } input:valid { border: 2px solid black; }
これは下記の更新があります。次のものを使ってみてください:
{{EmbedLiveSample("Validating_against_a_regular_expression", "100%", 80)}}
注: GitHub の fruit-pattern.html でライブサンプルを見ることができます(ソースコードも見てください)
この例では、{{HTMLElement("input")}} 要素は "banana"、"Banana"、"cherry" または "Cherry" という 4 つの文字列値のうち 1 つを受け付けます。正規表現は大文字小文字を区別しますが、中括弧にはさまれた"Aa"のパターンを使って小文字と同様に先頭が大文字のバージョンをサポートします。
この時点で、pattern
属性の中の値を以前に見たいくつかの例と同じ値に変更してみて、入力欄が有効になるように入力する値がどのように影響するかを確認してください。自分で考えた値も書いてみて、どのようになるか確認しましょう。果物に関する値を可能にすれば、例が分かりやすくなります。
もし {{HTMLElement("input")}} の空ではない値が正規表現パターンに一致しなかった場合、この input
は {{cssxref(':invalid')}} 疑似クラスに一致します。
メモ: {{HTMLElement("input")}} 要素の型によっては、検証のために pattern
属性が必要ないことがあります。例えば email
型を指定すると、入力された文字列を、妥当な形式のメールアドレスまたは、 multiple
属性がある場合はカンマで区切られたメールアドレスのリストであることを確認する正規表現で検証します。
メモ: {{HTMLElement("textarea")}} 要素は pattern
属性に対応していません。
あなたが、{{HTMLElement("input")}} または {{HTMLElement("textarea")}} によって作成してすべてのテキストフィールドで文字数を制限したいときには minlength
属性と maxlength
属性が使用できます。フィールドが値をもっており、その文字数が minlength
の値より少ないか、文字数が maxlength
の値より大きい場合は、フィールドは不正です。
ブラウザーはよくテキストフィールドに期待している以上に入力させないことがあります。単に maxlength
を使うよりも良いユーザーエクスペリエンスは、入力文字数のフィードバックを提供してサイズ以下でコンテンツを編集できるようにもしておくことです。例えば、Twitter の文字入力の制限があります。これは JavaScript と maxlength
を使った解決策の組合せで実現できます。
数値のフィールド (例えば <input type="number">
) の場合、min
属性と max
属性によって入力に制限を加えられます。もしそのフィールドの値がこの範囲を超える場合、そのフィールドは妥当ではありません。
他の例を見てみましょう。fruit-start.html ファイルの新しいコピーを作成してください。
では、<body>
要素の中身を削除して、以下のように置き換えてください。
<form> <div> <label for="choose">banana と cherry のどちらが好き?</label> <input type="text" id="choose" name="i_like" required minlength="6" maxlength="6"> </div> <div> <label for="number">どのくらい要ります?</label> <input type="number" id="number" name="amount" value="1" min="1" max="10"> </div> <div> <button>Submit</button> </div> </form>
text
フィールドには minlength
属性と maxlength
属性には 6 を指定しています。これは banana (バナナ) と cherry (さくらんぼ) の文字数と同じです。number
フィールドに min
属性で 1 を max
属性で 10 を指定しました。この範囲外の数字の入力は妥当ではないと表示されます。ユーザーは矢印を使ってこの範囲外の値に増減できませんが、ユーザーが数字を手入力した場合はデータは不正となります。この数字は必須ではないので、値を除去すると妥当になります。input:invalid { border: 2px dashed red; } input:valid { border: 2px solid black; } div { margin-bottom: 10px; }
例をライブで実行してみましょう。
{{EmbedLiveSample("Constraining_the_values_of_your_entries", "100%", 100)}}
注: GitHub の fruit-length.html でライブサンプルを見ることができます(ソースコードも見てください)
注: <input type="number">
(及び range
や date
のような他の型)は step
属性を取ることもでき、入力コントロール(数値の増加・減少ボタンなど)を使用するときに上げ下げすることができる値の刻みを設定することができます。上の例では step
属性を入れていませんので、既定値の 1
となります。つまり 3.2 のような浮動小数でも、不正になります。
HTML の内蔵検証機能の使い方を示す例の全体を示します。まずは HTML から:
<form> <p> <fieldset> <legend>Do you have a driver's license?<abbr title="This field is mandatory" aria-label="required">*</abbr></legend> <!-- While only one radio button in a same-named group can be selected at a time, and therefore only one radio button in a same-named group having the "required" attribute suffices in making a selection a requirement --> <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>
この HTML をスタイル設定する CSS は:
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; }
これで次のようにレンダリングされます。
{{EmbedLiveSample("Full_example", "100%", 420)}}
入力値と、それをサポートする入力タイプの制約に使える属性の完全なリストは、検証関連の属性を見てください。
注: GitHub の fruit-length.html でライブサンプルを見ることができます(ソースコードも見てください)
内蔵のエラーメッセージの見かけを制御したい場合や、HTML5 のフォーム検証に対応していないブラウザーに対処したい場合は、JavaScript を使用する必要があります。この節では、このようにするさまざまな方法を見ていきます。
多くのブラウザーが 制約検証API に対応しています。この API は各フォーム要素で使用できる一連のメソッドやプロパティで構成されています。
HTMLButtonElement
(<button>
要素を表現)HTMLFieldSetElement
(<fieldset>
要素を表現)HTMLInputElement
( <input>
要素を表現)HTMLOutputElement
(<output>
要素を表現)HTMLSelectElement
(<select>
要素を表現)HTMLTextAreaElement
(<textarea>
要素を表現)制約検証 API には、上記の要素で利用できる、次のプロパティがあります。
validationMessage
: コントロールが合格していない制約検証 (もしあれば) を説明するローカライズ済みのメッセージです。またはコントロールが制約の検証の対象ではない場合 (willValidate
が false
) または要素の値が制約に合格している場合は、空文字列です。validity
: 要素の検証状態を説明する ValidityState
オブジェクトです。取りうる検証状態の詳細は {{domxref("ValidityState")}}のリファレンスを参照してください。下記はよく使われるものを少し、一覧にしています:
true
を、マッチする場合 false
を返す。true なら、要素は {{cssxref(":invalid")}} CSS 擬似クラスにマッチする。true
を、同じ長さ以下の場合 false
を返す。true なら、要素は {{cssxref(":invalid")}} CSS 擬似クラスにマッチする。true
を、同じ長さ以上の場合false
を返す。true なら、要素は {{cssxref(":invalid")}} CSS 擬似クラスにマッチする。true
を、同じ大きさ以下の場合 false
を返す。true なら、要素は {{cssxref(":invalid")}} と {{cssxref(":out-of-range")}}CSS 擬似クラスにマッチする。true
を、同じ大きさ以上の場合 false
を返す。true なら、要素は {{cssxref(":invalid")}} と {{cssxref(":out-of-range")}}CSS 擬似クラスにマッチする。email
か url
のとき)は true
を、文法が正しい場合は false
を返す。true
なら、要素は {{cssxref(":invalid")}} CSS 擬似クラスにマッチする。valid
: 要素が検証制約をすべて満たす、ゆえに妥当とみなされる場合true
を、いずれかの制約を満たさない場合 false
を返す。true なら、要素は {{cssxref(":valid")}} CSS 擬似クラスにマッチする。そうでない場合は {{cssxref(":invalid")}} CSS 擬似クラスにマッチする。valueMissing
: 要素に {{htmlattrxref("required", "input")}} 属性があって値がない場合は true
を、そうでない場合 false
を返す。true なら、要素は {{cssxref(":invalid")}} CSS 擬似クラスにマッチする。willValidate
: フォームが送信されるときに要素が検証される場合に true
を返します。そうでない場合は false
を返します。制約検証 API には、上記の要素で利用できる、次のメソッドがあります。
checkValidity()
: 要素の値で妥当性の問題がない場合に true
を返します。そうでない場合は false
を返します。要素が不正である場合、このメソッドは要素で {invalid
イベントを発生させます。setCustomValidity(message)
: 要素に独自のエラーメッセージを追加します。独自のエラーメッセージを設定すると、要素が不正であるとみなされる場合に指定したエラーが表示されます。これにより JavaScript で、標準の HTML5 制約検証 API で提供されるもの以外の検証不合格状態を作り出すことができます。ユーザーに問題を報告する際に、メッセージが表示されます。上記の HTML5 の検証制約の例で見てきたように、ユーザーが不正なフォームを送信しようとするたびにブラウザーはエラーメッセージを表示します。このメッセージを表示する方法は、ブラウザーにより異なります。
これらの自動のメッセージには、2 つの欠点があります。
これらのメッセージの外見やテキストを変更するには、制約検証 API の最も一般的なユースケースです。この使用法を例で詳しく見てみましょう。
いくつかの簡単な HTML で開始します (空の HTML ファイルにこれを入力します; もしよければ、fruit-start.html を基礎としてもいいでしょう):
<form> <label for="mail">私にメールアドレスを教えてください:</label> <input type="email" id="mail" name="mail"> <button>Submit</button> </form>
このページに次の JavaScript を追加します:
const email = document.getElementById("mail"); email.addEventListener("input", function (event) { if (email.validity.typeMismatch) { email.setCustomValidity("I am expecting an e-mail address!"); } else { email.setCustomValidity(""); } });
ここでメールアドレス入力への参照を保管して、入力値が変更されるたびに制約コードが走るためのイベントリスナーを追加します。
制約コードの中で、メールアドレス入力の validity.typeMismatch
プロパティが true
かどうか、つまり値がメールアドレスの形式のパターンにマッチしていないかを確認します。その場合、カスタムメッセージとともに setCustomValidity()
を呼び出して、フォームを送信するときに、送信が失敗してカスタムエラーメッセージが表示されます。
validity.typeMismatch
が false
の場合、空文字で setCustomValidity()
メソッドを呼び出します。これは入力が妥当となり、フォームが送信されます。
次のもので試すことができます:
{{EmbedGHLiveSample("learning-area/html/forms/form-validation/custom-error-message.html", '100%', 80)}}
注: この例は GitHub の custom-error-message.html で見ることができます (ソースコードも見てください)。
これまでほんとうに簡単な例を見てきましたので、少し複雑な独自の検証を作成するために API を使用する方法を見ていきましょう。
始めに、HTML です。また、次のものに沿ってみてください:
<form novalidate> <p> <label for="mail"> <span>メールアドレスを入力してください。</span> <input type="email" id="mail" name="mail"> <span class="error" aria-live="polite"></span> </label> </p> <button>Submit</button> </form>
この簡単なフォームでは、ブラウザーの自動検証を無効にするために novalidate
属性を使用しています。これで、検証を制御するためにスクリプトを使用できます。ただし、これは制約検証 API の対応や CSS の疑似クラス {{cssxref(":valid")}}, {{cssxref(":invalid")}}, {{cssxref(":in-range")}}, {{cssxref(":out-of-range")}} の適用を無効にするわけではありません。つまり、データを送信する前にブラウザーが自動的なフォームの妥当性確認を行わないとしても、あなた自身で確認を行って、フォームの状態に応じたスタイル設定ができます。
検証する入力は <input type="email">
で、これは required
(入力必須)で、8文字の minlength
があります。これをわれわれのコードで確認して、それぞれカスタムエラーメッセージを表示させてみましょう。
<span>
要素の中にエラーメッセージを表示させようとしています。 <span>
にセットされた aria-live
属性は、スクリーンリーダーのような支援技術を使用している人々を含む皆に、独自のエラーメッセージを提示するようにします。
注: ここでの要点は、フォームに novalidate
属性をつけると、フォームがエラーメッセージのバブルを表示するのを停止して、その代わりDOM内にカスタムエラーメッセージを選択した方法で表示させられることです。
この CSS はフォームの見栄えを少し良くして、入力データが無効なときの見た目のフィードバックを提供します。
/* これはサンプルの見栄えをよくするスタイルです */ body { font: 1em sans-serif; width: 200px; padding: 0; margin : 0; } p * { display: block; } input[type=email]{ -webkit-appearance: none; 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 コードは独自のエラー検証を制御します。
// DOM ノードの選択法はたくさんあります。ここではフォーム自体、メールアドレス // 入力ボックス、そしてエラーメッセージを配置する span 要素を取得しています。 const form = document.getElementsByTagName('form')[0]; const email = document.getElementById('mail'); const error = document.querySelector('#mail + span.error'); email.addEventListener("input", function (event) { // ユーザーが何かを入力するたびに、メールアドレスのフィールドが妥当かを // 確認します。 if (email.validity.valid) { // エラーメッセージを表示している場合に、フィールドが妥当になれば // エラーメッセージを取り除きます。 error.textContent = ""; // メッセージの内容物をリセットします error.className = "error"; // メッセージの表示状態をリセットします } else { // If there is still an error, show the correct error showError(); } }); form.addEventListener("submit", function (event) { // ユーザーがデータを送信しようとするたびに、メールアドレスの // フィールドが妥当かをチェックします。 if (!email.validity.valid) { // フィールドが妥当ではない場合、独自のエラーメッセージを // 表示します。 showError(); // また、イベントをキャンセルしてフォームの送信を止めます。 event.preventDefault(); } }); function showError() { if(email.validity.valueMissing) { // If the field is empty // display the following error message. emailError.textContent = 'You need to enter an e-mail address.'; } else if(email.validity.typeMismatch) { // If the field doesn't contain an email address // display the following error message. emailError.textContent = 'Entered value needs to be an e-mail address.'; } else if(email.validity.tooShort) { // If the data is too short // display the following error message. emailError.textContent = `Email should be at least ${ email.minLength } characters; you entered ${ email.value.length }.`; } // Set the styling appropriately emailError.className = 'error active'; }
コメントがよく説明していますが、簡単にいうと:
showError()
を実行します。showError()
を実行し、preventDefault()
でフォーム送信を停止します。showError()
関数は、入力の validity
オブジェクトのさまざまなプロパティを使ってエラーがどれかを決めて、適当なエラーメッセージを表示します。こちらが実際の結果です。
{{EmbedGHLiveSample("learning-area/html/forms/form-validation/detailed-custom-validation.html", '100%', 150)}}
注: GitHub の detailed-custom-validation.html に例があります(ソースコード見てください)
制約検証 API はフォーム検証を制御するための強力なツールであり、HTML および CSS のみで検証を行うよりもはるかにユーザーインターフェイスをコントロールできます。
古いブラウザーやカスタムコントロールにおいて、制約検証 API を使用できない (または使用したくない)ことがあるでしょう。このような場合でも、フォームを検証するために JavaScript が使用できます。フォームを検証には、実際のデータの検証よりもユーザーインターフェイスの疑問が多くなります。
フォームを検証するために、あなたはいくつかの疑問を考えなければなりません。
これまでのことを説明するため、古いブラウザーでも動作するように前出のサンプルを作り直してみましょう。
ご覧の通り、HTML はほとんど同じであり、HTML5 の validation機能を取り除いただけです
<form> <p> <label for="mail"> <span>メールアドレスを入力してください。</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>
同様に、CSS も大きく変更する必要はありません。{{cssxref(":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 コードでは大きな変更があり、多くの面倒な作業が必要です。
// 古いブラウザーで 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.textContent = ""; 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.textContent = "I expect an e-mail, darling!"; error.className = "error active"; // 一部の古いブラウザーは event.reventDefault() メソッドをサポートしていません。 return false; } else { email.className = "valid"; error.textContent = ""; error.className = "error"; } });
結果は以下のようになります。
{{EmbedLiveSample("An_example_that_doesnt_use_the_constraint_validation_API", "100%", 130)}}
ご覧の通り、自分でで検証システムを構築するのは大変なことではありません。難しいのはクロスプラットフォームで、かつ作成するであろうあらゆるフォームで使用できる汎用的なものにすることです。フォーム検証を行うために利用できる、Validate.js のような多くのライブラリがあります。
この記事の最後に到着しましたが、最も大事な情報を覚えていますか? 次に進む前に、この情報を保持しているか検証するテストがあります — Test your skills: Form validation を見てください。
クライアント側のフォーム検証は、カスタムスタイル設定やエラーメッセージには複雑な JavaScript を必要としませんが、ユーザーについては注意深く考えることが必要です。ユーザーが正しいデータを入力できるよう支援することを、常に忘れないでください。最後に、以下のことを必ず行ってください。
フォームが正しく埋められたことをチェックしたら、送信することができます。次のデータ送信でカバーします。
{{PreviousMenuNext("Learn/Forms/UI_pseudo-classes", "Learn/Forms/Sending_and_retrieving_form_data", "Learn/HTML/Forms")}}