HTML5のinputに備わっている仕組みを使えばJSなしで簡単にバリデーションを行うことが可能です。
今回はそれを多少のデザイン含めて試したことと、JSとの干渉の可能性に関してです。
実現したいこと
- HTML5に備わっている機能を使ってバリデーション(未入力/メールアドレス妥当性)を行う
- バリデーションの結果として、注記の「必須」を装飾する
- JavaScriptは使わない
サンプル
後述するサンプルで概ね上記のようなフォームが作れます。
action属性は記載していないため送信機能はありませんから、適当に入力してもらえれば以下が確認できます。
- いずれにもrequired属性をつけて、未入力防止
- Emailはtype="email"属性をつけて、入力内容がメールアドレスとして妥当かチェック
- 入力時にリアルタイムにチェックされ、注記の内容が変化(「必須」から「必須 入力OK」に変わる)
なお、注記が変化するのはCSSの擬似クラスによるものです。
コード
<div class="form">
<form method="post">
<p class="item">
<label>
<input size="20" type="text" name="name" required placeholder="例: 山田 太郎" />
<span>お名前<span class="notice">必須</span></span>
<label>
</p>
<p class="item">
<label>
<input size="20" type="email" name="email" required placeholder="例: info@example.com" />
<span>Email<span class="notice">必須</span></span>
<label>
</p>
<p class="item">
<label>
<input size="20" type="Tel" name="tel" required placeholder="例: 00-000-000" />
<span>TEL<span class="notice">必須</span></span>
<label>
</p>
<p><input type="submit" value="送信" /></p>
</form>
</div>
.form {
padding: 1em;
border-radius: 5px;
background-color: #fff;
}
.item label {
display: flex;
flex-wrap: wrap;
}
.item label > * {
display: block;
width: 100%;
}
.item label > input {
order: 2;
border-radius: 3px;
border: 1px solid #aaa;
}
.item label > span {
order: 1;
margin-bottom: 3px;
}
.notice {
font-size: 12px;
line-height: 1;
display: inline-block;
margin-left: 5px;
padding: 2px;
color: #666;
border: 1px solid #666;
border-radius: 3px;
}
input:invalid + span .notice {
color: red;
border-color: red;
}
input:valid + span .notice {
color: green;
border-color: green;
}
input:valid + span .notice:after {
margin-left: .5em;
content: '入力OK';
}
HTMLもCSSもサンプルなので適当なため、実際に使う場合は適宜詳細を詰める必要があります。
今回重要なのは以下の2点。
- display:flex;でorderを使って要素の上下を入れ替える
- :invalidと:validで「必須」の装飾や文字を変更
参考
JSとの併用で起こりうる問題
HTML5のrequired属性をつけることで、JSでもNode.textContentを使わずに以下のような形で未入力チェックができます。
// submitにonclickで下記関数を記述した場合
function check(){
// element.validity.valueMissing はbooleanを返す ただしIE10+
// 通常はinputに内容が入力されているいないに関わらずfalse固定
// required属性をつけると、空欄でtrue、入力値があればfalse
// つまり、required属性をつけてvalueMissingの値の真偽値を判定すれば未入力かどうかが確認できる
if(element.validity.valueMissing){
console.log('未入力です');
//return falseで動作をキャンセルして送信させない
return false;
} else {
//return trueで送信
return true;
}
}
しかしHTML5のバリデーションと併用すると以下のような問題があります(原因等推測が間違っていたらごめんなさい)。
なお、上記例はonclickの場合ですが、addEventListener("click", check, false);であっても同様です。
- submitを押した際に送信をキャンセルしているので、HTML5のバルーン型のバリデーションが動作しない
- 空欄だけをチェックしている場合、JSのバリデーションは通過してもtype="email"のメールアドレス用バリデーションが働いて引っかかる
- メールアドレスのバリデーションをJSで追加する場合、type="email"と同じ正規表現でないと、結局HTML5の方のアラートが出る
ちょっとややこしいですが、上記を整理すると以下のようになります。
- JSでバリデーションの弾くと、HTML5のポップアップは表示されない
- メールアドレス妥当性チェックの場合、JS側を通過してもHTML5側で引っかかる可能性がある
メールアドレスの欄がなかったり、欄があってもtype="text"を使うことで上記のtype="email"の問題は回避できますが、シンプルにするなら以下のようにどちらか一方を使う方が良いかもと考えています。
- JSは使わずHTML5のバリデーションのみを用いる
- JSで検証する場合はnovalidate属性を使ってHTML5のバリデーションを止める
1の場合はHTML5に対応していないブラウザは素通りです。
2の場合も切り捨てた古いブラウザは素通りになりますが、ライブラリを使うなどで手厚く対応する場合は1よりも広い範囲で適用可能です。
2016年の記事ですが、以下ページに比較検討した内容が書かれていますので参考になるかと思います。
HTML5のEmailのバリデーション
上記に以下のような説明があります。
Browsers that support the email input type automatically provide validation to ensure that only text that matches the standard format for Internet e-mail addresses is entered into the input box. Browsers that implement the specification should be using an algorithm equivalent to the following regular expression:
/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}
[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
ブラウザごとに上記の正規表現に相当するアルゴリズムを実装することとあります。
required属性とnovalidate属性
formにnovalidate属性をつけると検証機能を止めることができますが、この状態でrequired属性をつけていたらどうなるのか?
試したところvalueMissing: trueになっていました。
なお、この値は以下のようにして確認できます。
console.log(element.validity);
// required 属性が指定されているのに要素の値がないことを示す Boolean です。
valueMissing: false
// 値が、(type が email や url の場合に)求められる構文規則に従っていないことを示す Boolean です。
typeMismatch: false
// 値が、指定された pattern と一致しないことを示す Boolean です。
patternMismatch: false
// 値が、HTMLInputElement や HTMLTextAreaElement オブジェクトの maxlength を超えていることを示す Boolean です。
// 注: Gecko では maxlength より長い値はそもそも入力できないので、true になることは決してありません。
tooLong: false
// 値が、HTMLInputElement や HTMLTextAreaElement オブジェクトの minlength を下回っていることを示す Boolean です。
tooShort: false
// 値が、min 属性で指定された最小値を下回っていることを示す Boolean です。
rangeUnderflow: false
// 値が、 max 属性で指定された最大値を超えていることを示す Boolean です。
rangeOverflow: false
// 値が、step 属性で決められた規則に合わないことを示す Boolean です。(つまり、step の値で割り切れないことを表します)
stepMismatch: false
// 入力値をブラウザが処理できないことを示す Boolean です。
badInput: false
// その要素のカスタム検証メッセージが、 setCustomValidity() メソッドによって空文字以外に設定されていることを示す Boolean です。
customError: false
// 要素が全ての制約の検証に適合し、有効であることを示す Boolean です。
valid: false
上記のコメントアウト部分は以下のページから引用となります。
formnovalidate属性とnovalidate属性
formnovalidate属性とnovalidate属性の違いに関しては上記ページ内の説明が一番わかりやすいように思います。
とりあえずの理解で良い場合は以下の点が重要かもしれません。
- formにnovalidate属性をつけると、そのformの全てのinputやsubmitにformnovalidate属性をつけたのと同じ状態になる
個別に対象を設定する場合はnovalidate属性を使わずに、各inputやsubmitにformnovalidate属性をつけることになります。
JSによるバリーデーションの参考例
当記事のここまでの流れとは関係しませんが、テーマ的には同じなので参考として記載します。
WAI-ARIAとJavaScriptを使った方法でアクセシビリティ方面からのアプローチであり、こちらから考えるのが本道かとかと思います。
結び
内容や英訳が間違ってましたらすみません。
HTML5のバリデーションを使うと決定するなら、古いブラウザ(IEなら9以下?)を完全に切り捨てるという決断でもあるので、ある意味では踏ん切りをつけるのに役に立つかもしれません。
JSが必要ないため、読み込みファイルが減らせて複数設置も簡単というのも良い点かと思います。
ただスマホで見たときにポップアップのデザインが微妙(バルーンの上側のpaddingが0のように見える)なので、その点はどうにかしてほしいですが。
バルーンのデザイン変更に関しては調査中です。
8人がこの記事を評価
役に立ったよという方は上の「記事を評価する」ボタンをクリックしてもらえると嬉しいです。
連投防止のためにCookie使用。SNSへの投稿など他サービスとの連動は一切ありません。