Tomomi Imura

Tomomi Imura

An Open Web advocate and front-end engineer, who loves everything mobile, and writes about HTML5, CSS, JS, UX, tech events, gadgets, etc. She unintentionally got 15min of fame by creating The HTTP Status Cats. Also, the opinions expressed here are solely her own and do not express the views or opinions of my employer.

Twitter LinkedIn Github Flickr

HTML5 Form Validation のカスタマイズ

Note: This article is written in Japanese for HTML5 Advent Calendar 2012. If you’d like to read this article in English, you can read the original post I wrote on November 21. (The article was originally written for: Nokia Code Blog). Thank you.


師走です。早いものですね。さて、HTML5 Advent Calendar 2012 2日目を書かせてもらうことになりました。元々この記事は Nokia Code Blog の一記事として私が11月21日に書いたものなのですが、クロスポスト可ということなので、せっかくですので今回はその日本語版として記事にしてみました。というわけで、HTML5 Form Validation CSS3、ウェブフォント、JavaScript を使ったカスタマイズ方法について書いています。

以前までならばユーザの入力フィールドの検証(バリデーション)は JavaScript もしくはサーバサイドで専用のロジックを書かねばばらなかったわけですが、HTML5 からは仕様に組み込まれるようになったために非常に簡単にできるようになりました。実装されるようになってかれこれ1年ほど経っているのですがその間に Internet Explorer など、サポートされるブラウザも増えてきました。まずこのバリデーションカスタム化についてのこの記事を読む前に、必須課目として HTML5 から新たに加わったフォームのインプット要素についての理解が必要ですので、基本をここここなどでおさらいをしておいてください。さらにバリデーションについての全般的な内容については、白石 俊平さんの書かれた、「HTML5で仕様になった入力値チェック+便利な3Tips」が非常にわかりやすいと思います。

フォームバリデーションの基本

例えば必須入力のフィールドが空の状態で送信された場合の検証。これは HTML5 では <input>required 属性を加えるだけで、下のように非常に簡単に書くことができます。

<form> 
  <input type="text" required> 
  <input type="submit" value="Submit"> 
</form> 

単純なデモを書いたので試してみてください。仕様がサポートされているブラウザ上でフィールドを空のまま送信するとエラーメッセージが表示、もしくはエラーを示す UI が現れます。
下のスクリーンショットは、左がデスクトップ IE10 (英語版)のデフォルト、右が IE10 モバイルの UI です。

Basic form validation (IE10) Basic form validation (IE10 Mobile)

IE10 モバイル版では、エラーメッセージの吹き出しが表示されず、空フィールドの枠が赤く表示されただけの仕様になっているのですが、そのフィールドが focus された状態でバーチャルキーボードが現れるので、ユーザビリティは損なわれていないようです。

このメッセージや吹き出しの UI は、ブラウザや環境言語によって異なります。下の画像は日本語版の Chrome から。
Basic form validation (Chrome JP)

それでは、これから 1) パターンマッチング、2) CSS3 でのビジュアル効果、3) カスタムのエラーメッセージ設定、を使ってフルカスタマイズしてみましょう。

パターンマッチング

pattern 属性では要素の値を正規表現と照合することができます。下は、6~12 文字のアルファベットと数字、句読点を含む文字セットを一致させる正規表現を使った例です。

<form> 
  <input id="username" type="text" pattern="[a-zA-Z0-9_-]{6,12}" autofocus required> 
  <input id="submit" type="submit" value="create"> 
</form> 

pattern 属性のデモコードを試してみてください。わざと無効になるように3桁の数字などを入力てみましょう。

CSS3 ユーザインターフェイスセレクタ

CSS ではいくつかの、UI 要素状態を表す UI セレクタ(疑似クラスや疑似要素)があります。その例として、:valid, invalid, in-range, out-of-range, required, optional, read-only, read-write が挙げられます。
これを使って、入力の有効/無効状態を赤と緑の色別に表示するようにしてみましょう。

:valid {
    color: green;
} 
:invalid {
    color: red;
} 

入力値が正しい形式に一致する時は緑、値が無効なときは入力値が赤で表示されます。サンプルで試してみましょう。

ウェブフォントアイコンを使う

この上さらに、チェックマークのついたアイコンを表示させてみましょう。せっかくですので画像アイコンを使わず CSS3 をフル活用してウェブフォントを使った応用をやってみましょう。
using webfont icon

ここでまた必須課目です!ここではちょっと変わった活用をしてみたいので、CSS3 ウェブフォントについてよくわからないという方は必ず先におさらいしておいてください。

さて、フリーのウェブフォントはいろいろあるのですが、ここでは IcoMoon が配布している Iconic という絵フォントを使います。このサイトの、IcoMoon App を使うとなんと自分の必要なものだけを選べ、それを軽量パッケージ化してくれるのです。

一旦フォントセットを作ったら、それを読み込む @font-face 規則を使って CSS を作成します。

@font-face {
    font-family: 'iconic';
    src: url('webfonts/iconic.eot');
    src: url('webfonts/iconic.eot?#iefix') format('embedded-opentype'),
         url('webfonts/iconic.svg#iconic') format('svg'),
         url('webfonts/iconic.woff') format('woff'),
         url('webfonts/iconic.ttf') format('truetype');
    font-weight: normal;
    font-style: normal;
}

疑似クラス :valid と、疑似要素 ::after (もしくは ::before)を一緒に使うと入力値が無効であった時にエレメントの後ろ(または前に)コンテントを表示するとこができます。では後ろにフォントアイコンを表示させてみましょう。

input 要素の後にアイコンを表示するのだから、input 要素と疑似クラスと疑似要素を全部一気につなげて input:valid::after としたいところですが、ちょっと待って!この input 要素 DOM にはドキュメントツリーコンテントがないので疑似要素をくっつけることができないのです。なのでここでは適当な要素、 span を使うことにします。

<input id="username" type="text" pattern="[a-zA-Z0-9_-]{6,12}" autofocus required>
<span class="icon-validation" data-icon="&#xe000"></span> 

data-* 属性を使って絵フォント値を指定してみましょう。ここでは span 中に data-icon というカスタム属性を作成して IcoMoon で作成した特定のフォントのキャラクター値を指定しています。

:valid + .icon-validation::before {
    content: attr(data-icon);
    color: green;
}

簡単な CSS ではありますがこの数行にはいろいろな意味を含んでいます。まず、+ は Adjacent Sibling (隣接)セレクタ、直後に後続する要素のみ指定しています。そして疑似要素のコンテントは定義されたカスタムデータ属性を使っています。この HTML5 カスタムデータ属性 (data-*) は、DOM ステートを保ったまま少量のプライベートデータを保存できるのです。確かに絵フォントキャラクターを ::before 疑似要素の、content プロパティで直接使うことはできるのですが、ルー大柴みたいに言ってみれば、この data-* を使ってデータバインディグする方法がセマンティックでベターだと思うぜ☆

カスタムエラーの設定

エラーメッセージの表示をカスタマイズするには大まかに2つの方法があります。

では簡単な方法から。これは title 属性を使ったインラインテキストを表示させる方法で、ここで指定されたテキストはデフォルトのエラーメッセージに下に表示されます。したの画像は Opera 12 です。

<input id="username" type="text" pattern="[a-zA-Z0-9_-]{6,12}" autofocus required 
       title="must be alphanumeric in 6-12 chars"> 

このデモで自分で試してみてください。

フルカスタム仕様には、ちょっとだけ DOM スクリプティング(ってか JavaScript)を使います。 メッセージを含む DOM ノードの validationMessage プロパティ値を変更することによって setCustomValidity メソッドでカスタムメッセージを指定することができます。

フォーム要素ノード上で checkValidity メソッドが入力フィールドを検証した際にその値が無効であった場合、そのノードで invalid イベントが発生されます。なので、ここでイベントリスナを登録してそこで入力フィールドが空もしくはミスマッチかを調べてやればよいのです。

input.addEventListener('invalid', function(e) {
    if(input.validity.valueMissing){
        e.target.setCustomValidity("PLZ CREATE A USERNAME, YO!"); 
    } else if(!input.validity.valid) {
        e.target.setCustomValidity("U R DOIN IT WRONG!"); 
    } 
}, false);

下の画像が Firefox 16 での結果です。

validity プロパティは、 valuevalueMissingtypeMismatch など、要素のバリデーション状態を boolean で示すプロパティを含む ValidityState オブジェクトを返します。(ValidityState についてもっと詳しく学びたい方のためにブログの最後にリンクを貼っておきます。)

このデモで実際にどう動くか見てみてください。コードを fork して是非自分でもほかの ValidityState オブジェクト状態がどういったふうに動くのか確かめてみてください。
JavaScript と title 属性を両方使うことも可能です。これも自分で試してみてください。

Put Them All Together

さてここでフルまとめデモを見てみましょう。Windows Phone 8 メトロ UI をちょっとまねたスタイルにしてみました。なのでモバイルからもぜひためしてみてね。

Demo URL QR
http://goo.gl/xKj0X

実は私が試してみたところ IE 10 にはちょっとした gotcha があるのです。まあ、IE なので落とし穴があって当たり前か、とも思うのですが。このデモの場合、どうもフィールドが unfocus するまでチェックマークアイコンが表示されないようなのです。テストした他のブラウザでは入力値が有効になり次第(このデモの場合、文字数が6文字になり次第)アイコンがちゃんと表示されます。

で、下の画像は Windows Phone 8 上の IE10 Mobile の実際のスクリーンショットです。

screenshot of IE10 mobile

ちょっと端折った箇所もあるのでわかりにくい所もあったかもしれませんが、これからのフォーム UX の参考になっていただけえたらうれしいです。あ、あと最後に。フォールバックについて書きませんでしたが、バリデーションがすべてのブラウザに実装されているわけではないので実際は送信されたデータはサーバサイドでもしっかり管理することが大切です。当然といえば当然なのですが念のため。

ではよいお年を(ってちょっとまだ早いか)。

Learn More

日本語

英語



comments powered by