HTMLフォームと制約検証の完全ガイド

この記事では、HTMLフォームフィールドとHTML5が提供する検証オプションについて説明します。また、CSSやJavaScriptを使用してこれらを強化する方法についても説明します。

制約検証とは何ですか?

各フォームフィールドには目的があります。そして、この目的はしばしば制約によって管理されます。つまり、各フォームフィールドに入力すべきでないもののルールです。例えば、emailフィールドは有効なメールアドレスを要求し、passwordフィールドは特定の種類の文字を要求し、最小の必要な文字数があります。そして、テキストフィールドには入力できる文字数に制限があります。

最新のブラウザには、これらの制約がユーザーによって遵守されているかを確認し、それらのルールが破られた場合に警告を発する機能があります。これを制約検証と呼びます。

クライアントサイド対サーバーサイドの検証

JavaScript言語の初期の年に書かれたほとんどのコードは、クライアントサイドのフォーム検証を処理していました。現在でも、開発者はフィールド値をチェックするための関数を書くために多くの時間を費やしています。現代のブラウザではこれはまだ必要ですか?おそらくそうではありません。ほとんどの場合、あなたが何をしようとしているかによって本当に依存します。

しかし、最初に大きな警告メッセージです:

クライアントサイドの検証は、アプリが時間と帯域幅を無駄にし、サーバーにデータを送信する前に一般的なデータ入力エラーを防ぐことができる親切です。サーバーサイドの検証の代わりにはなりません!

常にサーバーサイドでデータをサニタイズしてください。すべてのリクエストがブラウザから来るわけではありません。たとえそれがブラウザから来たとしても、ブラウザがデータを検証したという保証はありません。ブラウザの開発者ツールを知っている人は、あなたの愛情たっぷりのHTMLとJavaScriptをバイパスすることもできます。

HTML5入力フィールド

HTMLは次の機能を提供します:

  • <textarea> 複数行のテキストボックス用
  • <select> オプションのドロップダウンリスト用
  • <button> … ボタン用

しかし、最も頻繁に使用するのは<input>です:

<input type="text" name="username" />

type属性はコントロールのタイプを設定し、多くのオプションがあります:

type description
button a button with no default behavior
checkbox a check/tick box
color a color picker
date a date picker for the year, month, and day
datetime-local a date and time picker
email an email entry field
file a file picker
hidden a hidden field
image a button which displays the image defined by the src attribute
month a month and year picker
number a number entry field
password a password entry field with obscured text
radio a radio button
range a slider control
reset a button that resets all form inputs to their default values (but avoid using this, as it’s rarely useful)
search a search entry field
submit a form submission button
tel a telephone number entry field
text a text entry field
time a time picker with no time zone
url a URL entry field
week a week number and year picker

もしtype属性を省略したり、サポートされていないオプションがあれば、ブラウザはtextにフォールバックします。現代のブラウザはすべてのタイプをよくサポートしていますが、古いブラウザはまだテキスト入力フィールドを表示します。

他にも便利な<input>属性には以下があります:

attribute description
accept file upload type
alt alternative text for the image types
autocomplete hint for field auto-completion
autofocus focus field on page load
capture media capture input method
checked checkbox/radio is checked
disabled disable the control (it won’t be validated or have its value submitted)
form associate with a form using this ID
formaction URL for submission on submit and image buttons
inputmode data type hint
list ID of <datalist> autocomplete options
max maximum value
maxlength maximum string length
min minimum value
minlength minimum string length
name name of control, as submitted to server
pattern a regular expression pattern, such as [A-Z]+ for one or more uppercase characters
placeholder placeholder text when the field value is empty
readonly the field is not editable, but it will still be validated and submitted
required the field is required
size the size of the control (often overridden in CSS)
spellcheck set true or false spell-checking
src image URL
step incremental values in numbers and ranges
type field type (see above)
value the initial value

HTML出力フィールド

入力タイプだけでなく、HTML5は読み取り専用の出力も提供します:

  • output: 計算やユーザー操作の結果として得られるテキスト出力
  • progress: valueおよびmax属性を持つプログレスバー
  • meter: valueminmaxlowhigh、およびoptimum属性によって設定された値に応じて、グリーン、アンバー、レッドの間で変化するスケール

入力ラベル

フィールドには、関連付けられた<label>が必要です。要素を囲むことができます:

<label>your name <input type="text" name="name" /><label>

または、フィールドのidfor属性を使用してラベルにリンクします:

<label for="nameid">your name</label>
<input type="text" id="nameid" name="name" />

ラベルはアクセシビリティのために重要です。placeholderを使用して画面スペースを節約するフォームに遭遇したことがあるかもしれません:

<input type="text" name="name" value="" placeholder="your name" />

プレースホルダテキストは、ユーザーが何かを入力すると(たとえそれが単一のスペースであっても)消えます。フィールドが何を求めているかをユーザーに覚えさせるよりも、ラベルを表示する方が良いです!

入力動作

フィールドタイプと制約属性は、ブラウザの入力動作を変えます。例えば、number入力はモバイルデバイスで数値キーボードを表示します。フィールドはスピナーを表示し、キーボードの上下カーソル押下で値が増減します。

ほとんどのフィールドタイプは明らかですが、例外もあります。例えば、クレジットカードは数字ですが、増減スピナーは役に立たず、16桁の数字を入力する際に上下を押しやすいです。標準のtextタイプを使用する方が良いですが、inputmode属性numericに設定して、適切なキーボードを表示します。また、autocomplete="cc-number"を設定することで、事前に設定されたまたは以前に入力されたカード番号を提案します。

適切なフィールドtypeautocorrectを使用することで、JavaScriptでは難しい利点が得られます。例えば、一部のモバイルブラウザでは次のようなことができます:

  • カメラを使ってカードをスキャンしてクレジットカードの詳細をインポートする
  • SMSで送られた一度きりのコードをインポートする

自動検証

ブラウザは、typeminmaxstepminlengthmaxlengthpattern、およびrequired属性によって定義された制約に従って入力値を確認します。例えば:

<input type="number" min="1" max="100" required />

空の値を送信しようとすると、フォームの送信が阻止され、Chromeでは以下のメッセージが表示されます。

スピナーでは、1から100の範囲外の値を許可しません。数値でない文字列を入力すると、同様の検証メッセージが表示されます。すべてJavaScriptの1行も使わずに

ブラウザの検証を停止するには:

  • novalidate属性を<form>要素に追加する
  • formnovalidate属性を送信ボタンまたは画像に追加する

カスタムJavaScript入力の作成

新しいJavaScriptベースの日付入力コンポーネントを書いているなら、キーボードから手を離して立ち止まってください!

カスタム入力コントロールを作成することは難しいです。マウス、キーボード、タッチ、音声、アクセシビリティ、画面の寸法、そしてJavaScriptが失敗した場合に何が起こるかを考慮する必要があります。また、異なるユーザーエクスペリエンスを作成しています。おそらくあなたのコントロールはデスクトップ、iOS、Androidの標準の日付選択より優れていますが、慣れないUIは一部のユーザーを混乱させるでしょう。

開発者がJavaScriptベースの入力を作成する理由は主に3つあります。

1. 標準コントロールはスタイル付けが難しい

CSSスタイリングは限られており、入力をラベルの::beforeおよび::after疑似要素でオーバーレイするなどのハックが必要になることが多いです。状況は改善されていますが、機能よりフォームを重視するあらゆるデザインに疑問を呈してください。

2. 古いブラウザでは現代の<input>タイプがサポートされていない

本質的には、Internet Explorer のためにコーディングしているのと同じです。IE ユーザーは日付ピッカーを取得できませんが、YYYY-MM-DD 形式で日付を入力できます。クライアントが固執する場合は、IE のみにポリフィルを読み込んでください。モダンブラウザに負担をかける必要はありません。

3. これまで実装されたことのない新しい入力タイプが必要です

これらの状況はまれですが、常に適切な HTML5 フィールドから始めてください。彼らは速く、スクリプトがロードされる前に動作します。必要に応じてフィールドを段階的に強化できます。たとえば、JavaScript のかけらを使って、カレンダーアドベントの終了日が開始日より後になるようにすることができます。

要約: HTML コントロールを再発明することを避ける!

CSS 検証スタイリング

次の擬似クラスを入力フィールドに適用して、現在の状態に応じてそれらをスタイルすることができます:

selector description
:focus the field with focus
:focus-within an element contains a field with focus (yes, it’s a parent selector!)
:focus-visible an element has focus owing to keyboard navigation, so a focus ring or more evident styling is necessary
:required a field with a required attribute
:optional a field without a required attribute
:valid a field that has passed validation
:invalid a field that has not passed validation
:user-valid a field that has passed validation after the user has interacted with it (Firefox only)
:user-invalid a field that hasn’t passed validation after the user has interacted with it (Firefox only)
:in-range the value is within range on a number or range input
:out-of-range the value is out of range on a number or range input
:disabled a field with a disabled attribute
:enabled a field without a disabled attribute
:read-only a field with a read-only attribute
:read-write: a field without a read-only attribute
:checked a checked checkbox or radio button
:indeterminate an indeterminate checkbox or radio state, such as when all radio buttons are unchecked
:default the default submit button or image

入力のplaceholderテキストを::placeholder擬似要素でスタイルすることができます:

/* メールフィールドの青いプレースホルダー */
input[type="email"]::placeholder {
  color: blue;
}

上記のセレクターは同じ特異性を持っているため、順序が重要な場合があります。次の例を考えてみましょう:

input:invalid { color: red; }
input:enabled { color: black; }

無効な入力は赤いテキストですが、disabled属性を持つ入力にのみ適用されます— つまり、すべての有効な入力は黒です。

ブラウザはページの読み込み時に検証スタイルを適用します。たとえば、次のコードでは、すべての無効なフィールドに赤い境界線が与えられます:

:invalid {
  border-color: #900;
}

ユーザーは、フォームと対話する前に、厳然とした赤いボックスのセットに直面しています。最初の送信後や値が変更されると検証エラーを表示すると、より良い体験が提供されます。そこでJavaScriptが登場します…

JavaScriptと制約検証API

制約検証APIは、標準のHTMLフィールドチェックを強化できるフォームカスタマイズオプションを提供します。以下のことができます:

  • ユーザーがフィールドと対話するか、フォームを送信するまで検証を停止する
  • カスタムスタイリングでエラーメッセージを表示する
  • HTMLだけでは不可能なカスタム検証を提供する。これは、2つの入力を比較する必要がある場合によく必要になります。たとえば、メールアドレスや電話番号を入力するとき、「新規」と「確認」パスワードフィールドが同じ値であることを確認するか、1つの日付が別の日付より後であることを確認する場合などです。

フォーム検証

APIを使用する前に、コードはデフォルトの検証とエラーメッセージを無効にするために、フォームのnoValidateプロパティをtrueに設定する必要があります(novalidate属性を追加するのと同じです):

const myform = document.getElementById('myform');
myform.noValidate = true;

次に、フォームが送信されたときなどのイベントハンドラーを追加できます:

myform.addEventListener('submit', validateForm);

ハンドラーは、checkValidity()またはreportValidity()メソッドを使用してフォーム全体が有効であるかを確認できます。これらは、フォームのすべての入力が有効な場合にtrueを返します。(違いは、checkValidity()が制約検証の対象となる入力があるかどうかを確認することです。)

Mozillaのドキュメント説明:

各無効なフィールドでinvalidイベントがトリガーされます。これはバブリングしません: ハンドラはそれを使用する各コントロールに追加する必要があります。

// 送信時にフォームを検証する
function validateForm(e) {

  const form = e.target;

  if (form.checkValidity()) {

    // フォームが有効 - さらなるチェックを行う

  }
  else {

    // フォームが無効 - 送信をキャンセルする
    e.preventDefault();

  }

};

A valid form could now incur further validation checks. Similarly, an invalid form could have invalid fields highlighted.

フィールドの検証

個々のフィールドには以下の制約検証プロパティがあります:

  • willValidate: 要素が制約検証の候補である場合trueを返します。

  • validationMessage: 検証メッセージ。フィールドが有効な場合、これは空の文字列になります。

  • valitity: フィールドが有効である場合、ValidityState オブジェクトvalidプロパティがtrueに設定されます。無効の場合、falseの場合、以下のプロパティの1つ以上がtrueになります:

    ValidityState 説明
    .badInput ブラウザが入力を理解できない
    .customError カスタム有効性メッセージが設定されている
    .patternMismatch 値が指定されたpattern属性と一致しない
    .rangeOverflow 値がmax属性より大きい
    .rangeUnderflow 値がmin属性より小さい
    .stepMismatch 値がstep属性のルールに合わない
    .tooLong 文字列の長さがmaxlength属性を超えている
    .tooShort 文字列の長さがminlength属性未満である
    .typeMismatch 値が有効なメールアドレスまたはURLでない
    .valueMissing requiredの値が空である

個々のフィールドは以下の制約検証メソッドを持っています:

  • setCustomValidity(message): 無効なフィールドにエラーメッセージを設定します。フィールドが有効な場合は空の文字列を渡さなければなりません。そうしないと、フィールドは永久に無効のままになります。
  • checkValidity(): 入力が有効な場合に true を返します。valitity.valid プロパティも同じことを行いますが、checkValidity() はフィールド上で invalid イベントもトリガーするため便利です。

validateForm() ハンドラ関数は、各フィールドをループし、必要な場合に親要素に invalid クラスを適用することができます:

function validateForm(e) {
  const form = e.target;
  if (form.checkValidity()) {
    // フォームが有効 - さらなるチェックを実行
  }
  else {
    // フォームが無効 - 送信をキャンセル
    e.preventDefault();
    // invalid クラスを適用
    Array.from(form.elements).forEach(i => {
      if (i.checkValidity()) {
        // フィールドが有効 - クラスを削除
        i.parentElement.classList.remove('invalid');
      }
      else {
        // フィールドが無効 - クラスを追加
        i.parentElement.classList.add('invalid');
      }
    });
  }
};

HTMLでメールフィールドを定義したと仮定します。

<div>
  <label for="email">email</label>
  <input type="email" id="email" name="email" required />
  <p class="help">Please enter a valid email address</p>
</div>

スクリプトは、メールが指定されていないか無効な場合に<div>invalidクラスを適用します。CSSは、フォームが送信されたときに検証メッセージを表示または非表示にすることができます:

.help { display: none; }
.invalid .help { display: block; }
.invalid label, .invalid input, .invalid .help {
  color: red;
  border-color: red;
}

カスタムフォームバリデータの作成

以下のデモンストレーションは、ユーザー名とメールアドレス、電話番号、またはその両方を要求するコンタクトフォームの例を示しています:

これは、FormValidateという名前の汎用的なフォームバリデーションクラスを使用して実装されています。フォーム要素は、オブジェクトをインスタンス化するときに渡されます。オプションの第二パラメーターを設定できます:

  • trueは、ユーザーがフィールドと対話するたびに各フィールドを検証する
  • false(デフォルト)は、最初の送信後にすべてのフィールドを検証し、その後のフィールドレベルの検証が発生します
// コンタクトフォームの検証
const contactForm = new FormValidate(document.getElementById('contact'), false);

.addCustom(field, func)メソッドは、カスタム検証関数を定義します。以下のコードは、emailまたはtelフィールドのいずれかが有効であることを確認します(どちらもrequired属性を持たない):

// カスタム検証 - メールおよび/または電話
const
  email = document.getElementById('email'),
  tel = document.getElementById('tel');

contactForm.addCustom(email, f => f.value || tel.value);
contactForm.addCustom(tel, f => f.value || email.value);

A FormValidate object monitors both of the following:

  • focusoutイベントは、個々のフィールドをチェックします
  • フォームsubmitイベントは、すべてのフィールドをチェックします

両方とも.validateField(field)メソッドを呼び出し、フィールドが標準の制約検証を通過するかどうかを確認します。通過すると、そのフィールドに割り当てられたカスタム検証関数が順番に実行されます。すべてがtrueを返す必要があります。

無効なフィールドには、フィールドの親要素にinvalidクラスが適用され、CSSを使用して赤いヘルプメッセージが表示されます。

最後に、オブジェクトはフォーム全体が有効であるときにカスタムsubmit関数を呼び出します。

// カスタム submit
contactForm.submit = e => {
  e.preventDefault();
  alert('Form is valid!\n(open the console)');
  const fd = new FormData(e.target);
  for (const [name, value] of fd.entries()) {
    console.log(name + ': ' + value);
  }
}

また、標準のaddEventListenerを使用してフォームsubmitイベントを処理することもできます。FormValidateは、フォームが無効な場合に他のハンドラーが実行されないようにします。

フォームフィネス

フォームはすべてのウェブアプリケーションの基盤であり、開発者はユーザ入力を操作するために相当の時間を費やします。制約検証はよくサポートされており、ブラウザはほとんどのチェックを処理し、適切な入力オプションを表示できます。

推奨事項:

  • 可能な限り標準のHTML入力タイプを使用してください。minmaxstepminlengthmaxlengthpatternrequiredinputmode、およびautocomplete属性を適切に設定してください。
  • 必要に応じて、カスタム検証とメッセージを有効にするために少しJavaScriptを使用してください。
  • より複雑なフィールドの場合、標準入力を段階的に強化してください。

最後に:インターネットエクスプローラーを忘れてください!

もしあなたのクライアントが主にIEユーザーでない限り、独自のフォールバック検証機能を実装する必要はありません。すべてのHTML5の入力フィールドはIEで動作しますが、より多くのユーザーの努力が必要になる場合があります。(例えば、IEは無効なメールアドレスを入力したときに検出しません。)サーバー側でデータを検証する必要があるため、それをIEのエラーチェックの基盤として考慮してください。

HTMLフォームと制約検証に関するよくある質問(FAQs)

HTMLフォームの検証の重要性は何ですか?

HTMLフォームの検証は、ウェブ開発の重要な側面です。ユーザーがフォームに入力したデータが、サーバーに送信される前に特定の基準を満たしていることを保証します。これはデータの整合性を維持するだけでなく、入力されたデータの正確性に関する即時のフィードバックを提供することで、ユーザーエクスペリエンスを向上させます。フォームの検証がなければ、間違った、不完全な、さらには悪意のあるデータを受け取るリスクがあり、データの破損、セキュリティ侵害、システムクラッシュなど、さまざまな問題が発生する可能性があります。

HTML5はフォームの検証をどのように改善しますか?

HTML5は、フォームの検証をはるかに簡単かつ効率的にするために、いくつかの新しいフォーム要素と属性を導入しています。例えば、email、URL、numberなどの新しい入力タイプを提供し、入力データをタイプに基づいて自動的に検証します。また、required、pattern、min/maxなどの新しい属性を導入し、入力データに対するさまざまな制約を指定できるようにします。さらに、HTML5は、JavaScriptを使用してカスタム検証を実行できる組み込みの検証APIを提供しています。

JavaScriptを使用せずにフォームの検証を行うことはできますか?

はい、HTML5のみを使用して基本的なフォーム検証を実行できます。HTML5は、入力データに対するさまざまな制約を指定できる新しい入力タイプや属性を提供します。たとえば、required属性を使用してフィールドを必須にすることができ、pattern属性を使用して特定のフォーマットを強制することができ、min/max属性を使用して数値入力の範囲を設定することができます。ただし、より複雑な検証の場合は、JavaScriptを使用する必要がある場合があります。

HTML5のフォーム検証でエラーメッセージをカスタマイズするにはどうすればよいですか?

HTML5は、エラーメッセージをカスタマイズできる検証APIを提供します。ValidityStateオブジェクトのsetCustomValidityメソッドを使用して、フィールドのカスタムエラーメッセージを設定できます。このメソッドは文字列引数を取り、フィールドが無効である場合にフィールドの検証メッセージになります。このメソッドを呼び出すことで、無効なイベントに応答して、フィールドの検証に失敗したときにこのメソッドを呼び出すことができます。

HTML5のフォーム検証を無効にするにはどうすればよいですか?

novalidate属性をフォーム要素に追加することで、HTML5のフォーム検証を無効にできます。この属性が存在する場合、ブラウザはフォームが送信される際にフォームに対して検証を実行しません。サーバーサイドで検証を完全に処理したい場合や、カスタムJavaScriptを使用して検証を行いたい場合に役立ちます。

HTML5で複数のフィールドを一緒に検証するにはどうすればよいですか?

HTML5は、複数のフィールドを一緒に検証する組み込みの方法を提供していません。しかし、JavaScriptを使用してこれを実現できます。複数のフィールドの値をチェックし、必要な基準を満たしていない場合にカスタムの有効性メッセージを設定するカスタム検証関数を記述できます。この関数は、フォームの送信イベントやフィールドの入力/変更イベントに応答して呼び出すことができます。

HTML5で別のフィールドの値に基づいてフィールドを検証する方法は?

HTML5は、別のフィールドの値に基づいてフィールドを検証する組み込みの方法を提供していません。しかし、JavaScriptを使用してこれを実現できます。1つのフィールドの値を別のフィールドの値と比較し、一致しない場合にカスタムの有効性メッセージを設定するカスタム検証関数を記述できます。この関数は、フィールドの入力/変更イベントに応答して呼び出すことができます。

HTML5で非同期検証をどのように実行できますか?

HTML5は、非同期検証をボックスからサポートしていません。しかし、JavaScriptを使用してこれを実現できます。AJAXリクエストなどの非同期操作を実行し、結果に基づいてカスタムの有効性メッセージを設定するカスタム検証関数を記述できます。この関数は、フィールドの入力/変更イベントやフォームの送信イベントに応答して呼び出すことができます。

HTML5のフォーム検証でエラーメッセージのスタイルをどのように設定できますか?

エラーメッセージの外観は、HTML5のフォーム検証においてブラウザによって決定され、CSSを直接使用してスタイル付けすることはできません。しかし、JavaScriptを使用してカスタムエラーメッセージを作成し、好みのようにスタイル付けすることは可能です。フィールドが無効であることを判断し、それに応じてカスタムエラーメッセージを表示するために、検証APIを使用できます。

HTMLフォームの検証をどのようにテストできますか?

HTMLフォームの検証をテストするには、フィールドに様々なタイプのデータを入力し、フォームの送信を試みることができます。検証がすべてのケースで正しく機能することを確認するために、有効なデータと無効なデータの両方でテストする必要があります。また、自動化されたテストツールやライブラリを使用して、より包括的なテストを実行することもできます。

Source:
https://www.sitepoint.com/html-forms-constraint-validation-complete-guide/