お疲れ。今日も今日とて、デザインカンプ通りにピクセルパーフェクトを叩き出しつつ、アクセシビリティの怪しい実装と格闘していることだろう。
さて、今回はフォームのバリデーション、その中でも地味ながらも強力な武器である `:valid` 疑似クラス について深掘りしていこうと思う。
「入力内容が正しいときにスタイルを当てるやつでしょ? `input:valid` とかで緑色の枠線出すやつね」
……そう思ったそこのあなた。半分正解で、半分は大怪我するフラグが立っている。
実務でフォームを実装する際、ページの読み込み直後や、ユーザーがまだ何も入力していない「初期状態」の `` に `:valid` がヒットしてしまい、ページを開いた瞬間からフォーム中が「入力完了です!」と言わんばかりの緑色に染まった、なんてホラー体験はないだろうか?
今回は、ブラウザの裏側の挙動を紐解きながら、現場で本当に使える `:valid` の処世術を伝授しよう。
—
1. そもそも `:valid` 疑似クラスとは何か?(仕様の再確認)
`:valid` は、HTMLのバリデーション属性(`required`, `type=”email”`, `type=”url”`, `minlength`, `pattern` など)の制約を満たしているフォーム要素にマッチする疑似クラスだ。
DOMの標準仕様において、要素がバリデーションエラーを起こしていない状態であれば、この `:valid` が付与される。逆にエラーがあれば `:invalid` だ。
ここで重要なのは、「何も入力されていない空の要素(requiredなし)」は、デフォルトでバリデーションを通過(valid)とみなされる という仕様のトラップだ。
ブラウザの裏側で何が起きているか?
ブラウザのレンダリングエンジン(Blink, Gecko, WebKitなど)は、フォーム要素が生成されると同時に内部で `ValidityState` というインターフェースを保持している。
この中には `valueMissing`, `typeMismatch`, `patternMismatch` などのフラグがあり、これらがすべて `false` のとき、ブラウザは「よし、この要素は valid だ」と判断し、CSSの `:valid` セレクタをツリーに適用する。
つまり、初期状態の空っぽの `input`(`required` が無い場合)は、エラーフラグが立っていないため、容赦なく `:valid` の世界へ放り込まれるというわけだ。
—
2. 現場でありがちな「やっちまった」実装
まずは、よくある失敗例を見てみよう。
/ 悪い例:初期状態から緑のボーダーが出てしまう /
input:valid {
border-color: #10b981; / 成功時の緑色 /
}
input:invalid {
border-color: #ef4444; / エラー時の赤色 /
}
このコードを書いてブラウザでフォームを開いた瞬間、どうなるか?
ユーザーがまだキーボードに触れてすらいないのに、すべての入力欄が「入力完了」の緑色に染まるか、あるいは必須(`required`)の赤色に染まる。これではユーザービリティの観点から最悪だ。「まだ何も書いてないのに怒られた」「入力してないのに褒められた」というカオスな状態になる。
私たちフロントエンドエンジニアが目指すべきは、「ユーザーが入力アクションを起こした後(あるいはフォーム送信を試みた後)」に、適切にフィードバックを返すスマートなUIだ。
—
3. 実務で使える!`:valid` を飼いならすベストプラクティス
では、どうすればこの初期状態の「誤爆」を防げるのか?
答えはシンプルで、「ユーザーが一度でもそのフィールドに触れた(インタラクトした)」、あるいは「フォーム送信を試みた」という文脈をCSS側でフックすることだ。
ここに、現代CSSの強力な疑似クラス(`:user-invalid`, `:placeholder-shown` など)を組み合わせる。
アプローチA:`:placeholder-shown` との合わせ技(王道テクニック)
まだユーザーが入力していない(プレースホルダーが表示されている)状態のときは、`:valid` がついていてもスタイルを打ち消す、というアプローチだ。
/ プレースホルダーが表示されている(=未入力)のときは、validであっても装飾しない /
input:valid:not(:placeholder-shown) {
border-color: #10b981;
background-image: url(‘data:image/svg+xml,…’); / チェックマークのアイコンなど /
}
/ エラー時も同様に、未入力の初期状態では赤くしない工夫が必要 /
input:invalid:not(:placeholder-shown) {
border-color: #ef4444;
}
この手法のミソは `:not(:placeholder-shown)` だ。ユーザーが1文字でも入力した瞬間にプレースホルダーが消えるため、そこから初めて `:valid` や `:invalid` の真価が発揮される。
—
4. コピペで使える!実践フォームコンポーネントのサンプル
実際にプロダクトでそのまま使えるレベルの、リッチなCSS設計のサンプルコードを置いておく。
HTMLの構造とあわせて確認してほしい。
HTML
※注: ブラウザ標準のネイティブツールチップを抑止するために、`

コメント