【実務・中級編】 :valid と :invalid 疑似クラス – CSS実践ガイド

CSSの力でフォーム体験を極める:`:valid` と `:invalid` を使いこなす現場の流儀

フロントエンドの現場で「フォームバリデーション」という言葉が出た瞬間、多くのエンジニアは真っ先に JavaScript のバリデーションライブラリを思い浮かべるはずだ。`yup` や `zod` でスキーマを定義し、状態を管理し、エラーメッセージを出し分ける……。もちろん、それは正しい。

しかし、腕の立つフロントエンド・アーキテクトならこう考えるはずだ。「CSSだけで完結できるUXの向上を、わざわざJSに持ち込んでコストを払う必要はあるか?」と。

今回は、現代のブラウザが標準で備えている `:valid` と `:invalid` を使い倒し、JavaScriptに頼りすぎない「堅牢で美しいフォーム」を作るための知見を共有しよう。

—

ブラウザの裏側:なぜこれが最強の選択肢なのか

そもそも `:valid` と `:invalid` は、ブラウザが HTML5 のバリデーション機能(`required`, `type=”email”`, `pattern` 属性など)を解釈した結果、その要素が満たされているかどうかを自動判定する疑似クラスだ。

ここが重要なのだが、ブラウザはページが読み込まれた瞬間から、ユーザーがキーを叩くたびに、裏側で常にこの判定を回している。

多くのジュニア層は、これを「エラーメッセージを出すためのツール」としか見ていない。だが、真のプロはこれを使って「入力のフィードバックループ」を CSS だけで完結させる。JSの再レンダリングを待たずに、ユーザーが文字を打った瞬間に枠線が赤から緑に変わる。このレスポンスの速さが、UIの信頼性に直結するんだ。

実践:コピペで使える「脱・JSバリデーション」スタイル

まずは、現場ですぐに使える洗練されたパターンを見てほしい。単に赤くするだけではUXとして不十分だ。フォーカス時にエラーを出すタイミングを制御し、ユーザーの「入力中に怒られるストレス」を緩和するのがポイントだ。

/ フォームの基本スタイル /
.input-field {
display: block;
width: 100%;
padding: 12px;
border: 2px solid #ccc; / デフォルトはニュートラルに /
border-radius: 4px;
outline: none;
transition: border-color 0.2s ease;
}

/

  • ポイント1: :invalid は「入力中」には適用させないのがコツ
  • :not(:placeholder-shown) を組み合わせることで、
  • 何も入力していない初期状態のエラー表示を防ぐ

/
.input-field:invalid:not(:placeholder-shown) {
border-color: #ff4d4f;
background-color: #fff2f0;
}

/

  • ポイント2: :valid で正解を視覚的にフィードバック
  • ユーザーは「正しく入力できている」という確信が持てると安心する

/
.input-field:valid:not(:placeholder-shown) {
border-color: #52c41a;
}

/

  • ポイント3: エラーメッセージの出し分け
  • 隣接セレクタを使って、エラー時のみメッセージを表示させる

/
.error-message {
display: none;
color: #ff4d4f;
font-size: 0.85rem;
margin-top: 4px;
}

.input-field:invalid:not(:placeholder-shown) + .error-message {
display: block;
}


有効なメールアドレスを入力してください。

—

現場で直面する「落とし穴」への対策

この手法を使いこなす上で、シニアとして君たちに伝えておきたい「泥臭い現実」が2つある。

1. 空白時の挙動を制御せよ

`:invalid` は `required` が付いている要素が空の時も適用される。しかし、ユーザーがフォームをクリックした直後に赤色が出るのはUXとして最悪だ。上述のサンプルで `:not(:placeholder-shown)` を入れているのはそのためだ。あるいは、`:focus` と組み合わせて「フォーカスが外れたタイミング(`:focus:invalid`)」でエラーを表示させるのも戦略の一つだ。

2. ブラウザのデフォルトUIを消す

`type=”email”` などを使うと、ブラウザ標準のツールチップ(「メールアドレス形式で入力してください」といった吹き出し)が邪魔になることがある。これを消すには、フォーム要素ではなく `

` タグに `novalidate` 属性を付与するのが定石だ。


最後に:CSSは「状態」を記述する言語だ

フロントエンドのアーキテクチャにおいて、「DOMの属性(状態)」と「スタイル」を同期させるのは、もっともバグが少なく、パフォーマンスが高いアプローチだ。

JavaScript で `isError` のような state を管理し、それを `className` に反映させ、再レンダリングを走らせる……。それも一つの手法だが、ブラウザが提供しているネイティブな `:valid / :invalid` を活用することは、コード量を減らし、ブラウザの最適化を最大限に引き出す「プロの選択」だ。

まずは次のプルリクエストで、バリデーションロジックの一部をCSSに逃がしてみるといい。チームのメンバーが「なぜこんなにコードがスッキリしているんだ?」と驚くはずだ。それが、君が技術の核心を捉えた証拠になる。

コメント

タイトルとURLをコピーしました