はじめまして、技術ブログ初投稿のキャスレーコンサルティングのSD(システム・デザイン)部・瀬戸口です。
フロント技術とデザインが好きなエンジニアです。よろしくお願いします。
今回は、HTML5で新たに実装された機能「フォームバリデーション」について、少し触ってみたのでご紹介します。
長年HTML4に慣れ親しんだ身としては、HTML5でフォームバリデーションができる!と知った時、とても感動しました。
是非実務にも取り入れたいと思ったので、どういった使い方をすると良さそうか、また、何に注意すべきかを検証してみました。
従来のフォームバリデーション
今までのHTML4単体では、バリデーション機能はありませんでした。
したがって、一般的にはHTMLは画面から受け取った文字列を渡すだけで、バリデーションチェックは主にJavaScriptとサーバーサイドの役目でしたね。
具体的な方法として色々ありますが、たとえば…
- サーバーサイド言語のフレームワークに付属している、バリデーション機能を利用する
- バリデーション専用のAPIを実装してチェックする
- ホワイトリスト方式で、最小限の文字列だけをマッチングする
- JavaScriptを利用して、リアルタイムで入力チェックする
など、セキュリティ度の高さや目的によって、様々な形で対応してきました。
このブログでは、サーバサイドの話は一旦置いておき、ブラウザサイドに注目します。
従来のHTML4で実現していたものをHTML5で実現し、ブラウザサイドでできること、できないこと、注意することなどを検証してみます。
(※2016年7月時点での情報です)
HTML4でチェック
今回は、こんなフォームを用意してみました。
仕様は、
- 入力しながら、バリデーションチェックをします
- 氏名とメールアドレスは必須入力です
- メールアドレスと電話番号はそれぞれ決まった形式で入力を促します
使用したものは、
- HTML4
- CSS
- JavaScript(jQuery + jquery.validate.js プラグイン)★バリデーションチェック ★入力補助
バリデーションチェックにjquery.validate.jsを利用しています。
(主にjsでバリデーションの設定をするため、HTMLタグを殆ど汚すことなく、分けて管理できます。)
また、ユーザの入力補助の制御(エラー文言の表示など)も、JavaScript(と一部CSS)が担います。
HTML
<form action="hoge.php"> <div> <p class="req">氏名</p> <input type="text" name="text"> </div> <div> <p class="req">メールアドレス</p> <input type="text" name="email"> </div> <div> <p>電話番号</p> <input type="text" name="tel"> </div> <div> <p>弊社を何でお知りになりましたか?</p> <ul> <li><label><input type="checkbox" value="c_official">弊社の公式ウェブサイト</label></li> <li><label><input type="checkbox" value="c_blog">技術ブログ</label></li> <li><label><input type="checkbox" value="c_friend">友人の紹介</label></li> <li><label><input type="checkbox" value="c_other">その他</label><br /> <input type="text" name="otherComment" id="otherComment"></li> </ul> </div> <button type="submit">送信する</button> </form>
ポイントは、HTML4で1行のテキスト入力は、文字列・数字・ローマ字など、どんな項目でも「type=”text”」を利用している点です。すべての入力内容を、ただの文字列として送信する役割になっています。
HTML単体でバリデーションチェックができないため、JavaScriptで実装します。メールアドレスと電話番号には、下記の正規表現を設定しています。
JavaScript(抜粋)
var methods = { email: function(value, element){ return this.optional(element) || /[\w\d_-]+@[\w\d_-]+\.[\w\d._-]+/.test(value); }, tel: function(value, element){ return this.optional(element) || /^\d{11}$|^\d{3}-\d{4}-\d{4}$/.test(value); } };
メールアドレスは、「@」を含む英数字と特定の記号で構成された文字列。
電話番号は、11桁の数字またはハイフン込みの入力規則を表します。
それぞれの入力規則にマッチしない場合、エラーが表示される仕組みです。
入力
下記のような表示になります。きちんとバリデーションチェックできていることが確認できます。
正しく入力 | 誤った入力 |
メリット
- バリデーションに実績のあるプラグインが豊富
- 対応ブラウザの数が多い
- サーバーサイドに送信することなく、入力値に応じて即時チェックできる
デメリット
- プラグインの利用により管理するソースコードの量が増え、バージョンに依存する
- デベロッパーツールでの改竄と不正リクエストができてしまう
総評
3段階評価で、大体下記のような使い心地です。
機能面
機能性は十分ですね。幅広く利用されるのも納得の使い心地です。
安全性は、デベロッパーツールでの改竄と不正リクエストができてしまうので、セキュリティ面を重視する場合は、サーバーサイドのチェックがあると安心です。
速度はプラグインを介すので若干下がりますが、体感ではほとんど感じない程度です。
開発面
比較のため、これを基準とします。
HTML5でチェック
上記の仕様を、HTML5とCSSだけで実装するとどうなるか試してみました。
見た目も仕様も、ほぼ同じです。
と、ここでお気づきの方も多いと思いますが、テキストの入力フォームの中に、薄い文字が入っていますね。
今となってはすっかりおなじみの、プレースホルダー(placeholder)です。この属性も、ユーザの入力を助けてくれる、HTML5から追加されたスグレモノです。(これも、昔はJavaScriptで出したり消したりしてたんですよね…)
使用したものは、以下です。
- HTML5 ★バリデーションチェック
- CSS ★入力補助
JavaScriptで行っていた2つの役割を、HTML5とCSSで分担しています。
HTML
<form action="hoge.php"> <div> <p class="req">氏名</p> <input type="text" placeholder="氏名" name="text" required autoforcus /> <p class="error"> <span class="invalid">(!) 名前を入力して下さい</span> </p> </div> <div> <p class="req">メールアドレス</p> <input type="email" placeholder="メールアドレス" name="email" pattern="[\w\d_-]+@[\w\d_-]+\.[\w\d._-]+" required /> <p class="error"> <span class="invalid">(!) 正しいメールアドレスの形式で入力して下さい</span> </p> </div> <div> <p>電話番号</p> <input type="tel" placeholder="電話番号" name="tel" pattern="^\d{11}$|^\d{3,4}-\d{3,4}-\d{4}$"/> <p class="error"> <span class="invalid">(!) 正しい電話番号の形式で入力して下さい</span> </p> </div> <div> <p>弊社を何でお知りになりましたか?</p> <ul> <li><label><input type="checkbox" value="c_official">弊社の公式ウェブサイト</label></li> <li><label><input type="checkbox" value="c_blog">技術ブログ</label></li> <li><label><input type="checkbox" value="c_friend">友人の紹介</label></li> <li><label><input type="checkbox" value="c_other">その他</label><br /> <input type="text" name="otherComment" id="otherComment" placeholder="ご記入ください"></li> </ul> </div> <button type="submit">送信する</button> </form>
HTML5では、inputタグの属性が新たに増えています。利用しているものについて、少し解説します。
HTML5から追加された、inputタグの属性
- type属性:emailプロパティ
- メールアドレスを入力するテキストボックスを生成する
- type属性:telプロパティ
- 電話番号を入力するテキストボックスを生成する
- placeholder属性
- 何を入力するテキストボックスなのか、指定した文字を表示する
- pattern属性
- 入力文字列に対して適用する正規表現を指定す
- autoforcus属性
- ページ読み込み時にフォーカスする
- required属性
- 必須入力を促す
参考URL:input 要素 – HTML | MDN
※その他の属性、対応ブラウザ等については、上記URLをご参照ください。
type属性のemailプロパティのデフォルトでは「アットマークを含む、その前後に1文字以上の文字列(英数字と._-)が存在する」条件のようなので、きちんと評価したい場合はpattern属性で細かく指定します。
type属性のtelプロパティについても入力パターンの制約が特にないので、pattern属性で同様に指定しています。
また、今回は検証環境がWindowsPCなのですが、フォーカスするとtype=”text”では従来どおり入力モードが「全角ひらがな」になるほか、type=”email”、type=”tel”では「半角英数字」に自動的に変化します。
ちなみに、スマートフォンではtype=”email”が「半角英字(1文字目は小文字)」、type=”tel”が「数字」になります。非常に便利です。
CSS
/* NGなら赤くする */ form input:focus:invalid { border : tomato 2px solid; } /* 操作中、入力値が正しい場合は、不正エラーを消す */ form input:focus:valid + .error .invalid { display : none; } /* OKなら、その他のテキストボックス以外を緑にする */ form input:valid:not(:last-child) { border : seagreen 2px solid; }
なんとHTML5では、入力した結果に応じて、表示も切替出来るようになっています!
擬似クラスを用いて実装してみました。利用しているものについて、少し解説します。
HTML5向けに追加された、擬似クラス
- :valid
- バリデーションに成功したコンテンツを持つ要素
- :invalid
- バリデーションに失敗したコンテンツを持つ要素
- :required
- required属性を持つ要素
- :not(セレクタ)
- 指定した要素以外の要素
- :last-child
- 自身の親要素の最後の子要素
参考URL:疑似クラス (Pseudo-classes) – CSS | MDN
入力
下記のような表示になります。きちんとバリデーションチェックできていることが確認できます。
正しく入力 | 誤った入力 |
HTML5ではsubmitボタンを押下し、バリデーションエラーが起きた時、サーバへ送信される前に止められます。
その時に出現するエラー表示のポップアップはブラウザごとにデザインが異なり、今のところメッセージをカスタムする方法はあるようです。
見た目デザインをカスタムする方法は、探したところ見当たらなかったので、あったら是非教えてください。
メリット
- HTML + CSS だけで簡単に実装できるので、JavaScriptに比べて記述するソースコードの総量が減る
- JavaScriptがオフでも、バリデーションチェックができる
- DOM操作やJavaScriptの実行がない分、処理が速い
- スマートフォン対応している属性やプロパティがある
- サーバーサイドに送信することなく、入力値に応じて即時チェックできる
デメリット
- 属性のブラウザ対応状況が少ないため、使用ブラウザの縛りがある
- デベロッパーツールでの改竄と不正リクエストができてしまう
総評
3段階評価で、大体下記のような使い心地です。
機能面
最新の技術ということもあり、ブラウザ対応がまだ少ないですが、よく利用されるtype属性の「search」「tel」「url」「email」は他のプロパティに比べて対応済みのようなので、最新の環境では使えそうです。
正確性はpattern属性の正規表現との組み合わせで、手軽にホワイトリスト形式のマッチングが可能です。
安全性はHTML4の時と同様です。
参考URL:Web Designer’s Checklist の「HTML5 Forms Inputs」
参考URL:input 要素 – HTML | MDN
開発面
HTMLのtype属性とpattern属性で指定するだけなので、バリデーションチェック機能をとても簡単に実装できるようになりました!HTMLであれば、バージョン管理に悩まされることも少なく、今後末永く利用できるのも魅力ですね。
また、プレースホルダーや、オートフォーカス、入力値の評価まで、今までJavaScriptで制御していたものが、HTMLとCSSの擬似クラスで実現できてしまう手軽さも加わった分、Javascirptを導入するときに比べて開発コストも少なめに抑えられるでしょう。
おまけ
未対応ブラウザでのバリデーションチェックをカバーする際には、まだまだJavaScriptの助けは必要になります。
この場合、HTML側のフォームバリデーション機能が邪魔をしてしまうので、オフにする場合は下記のように記述します。
<input type="submit" formnovalidate>
今後もブラウザの進化と共に、対応範囲が広がってくれたら嬉しいですね。
参考URL:HTML5 input type のブラウザ対応について検証してみた。
触れてみた感想
さて、長々と2つの実装パターンを解説してまいりました。
技術的な話はこの辺にして…最後に少しだけお付き合いください。
セキュリティ的な観点からみて、サーバーサイドでのバリデーションチェックはどうしても必要ということがわかりました。現時点では、本来のバリデーションとしての機能も、十分とはいえない印象です。では、HTML5でバリデーションチェック機能を利用することに意味はあるのか?どんな意図で、この機能が実装されたのか?と、ふと疑問に思いました。
ここからは個人的な推測になるのですが、上記の実験を通して、「バリデーションチェックでデータそのものの妥当性をHTML5で評価する」ことよりも、「ユーザの入力補助機能をHTML5で簡単に実装する」ことを目的としているように感じました。
入力フォームのエラーは大きく2種類あると思っています。
1)単純な入力ミスによる、ヒューマンエラー
2)XSSのような悪意を持った、入力エラー
私は、ユーザとの接点を支えるインターフェイスとして実装されているのが、HTMLとCSSだと思っています。したがって、本来、入力ミスによるヒューマンエラーは、サーバーサイドに送られてチェックされる前に防ぐべきものだと思うのです。
今まではそれをJavaScriptやサーバサイドがXSSのような入力エラーと共に処理し、入力に応じてエラーを表示させ、注意を促すといった実装をしてきましたが、それがHTMLとCSSでできるようになり、HTMLとCSSのインターフェイスとしての役割がようやく全うできるようになってきた…ように思えて、ちょっと素敵な未来を感じました。
PCに限らず、様々なデバイスでの利用が増えていますが、そのような環境でも親切な動きをしてくれるようになってきているのも、大きな進化だと感じました。
更なるユーザビリティの向上が期待できそうなので、ブラウザ対応等に気を配りつつ、積極的に利用していきたいです。