おい、最近フォーム周りの実装で「JavaScriptでちまちま入力必須チェックをして、ご丁寧にクラスを付け外ししているコード」を見かけてだな、思わずコーヒーを吹き出しそうになったんだよ。
「いやいや、君、ブラウザのネイティブ機能忘れてないかい?」ってね。
現代のフロントエンド開発において、フォームのバリデーションや必須項目のスタイリングをJSだけに頼るのは、ぶっちゃけ車輪の再発明どころか、メンテナンスコストをドブに捨てるようなもん。HTML側でちゃんと `required` 属性を打ってあるなら、CSSの `:required` 疑似クラスにバトンを渡せば、ブラウザが裏側でいい感じに全部さばいてくれる。
今回は、この `:required` 疑似クラスについて、実務で明日から即座に使える「生きた知見」を叩き込んでやろうと思う。準備はいいか?それじゃあ、いってみよう。
—
1. `:required` 疑似クラスの基本と、ブラウザの裏側の動き
まずは基本のおさらいだ。`:required` は、その名の通り、``、`
ブラウザはどうやってこいつを処理しているのか?
CSSセレクタがパースされるとき、ブラウザのレンダリングエンジンはDOMツリーの各要素が持つ属性(Attribute)やプロパティ(Property)をチェックしている。`:required` の場合、要素が `required` 属性(あるいは対応するIDL属性)を持っているかどうかを判定基準にしているんだ。
特筆すべきは、これが「静的な属性の有無」だけでなく、HTML5のフォームバリデーション機構と密に連携しているという点。つまり、ブラウザは「このフィールドが必須入力である」というステータスを裏側で常にトラッキングしていて、アクセシビリティツリー(A11y)やフォーカス管理とも連動させている。ここをCSSから直接叩けるんだから、使わない手はないよね。
—
2. 実務で遭遇する「罠」と、シニアが教えるベストプラクティス
さて、ここからが本題だ。教科書通りに `:required` を使うだけなら誰でもできる。だが、現場でこれをやると、デザイナーやディレクターからこう言われるんだ。
> 「ページを開いた瞬間から、必須の入力欄全部に赤いエラーの枠線が出てるんだけど!これ、まだ何も入力してないよね?」
……そうだ。ここに大きな罠がある。
`:required` は「必須属性がついている要素」を無条件で選択する。ユーザーがページを開いた直後、まだ何も入力していない状態であっても、`:required` は容赦なくマッチしてしまう。
初期表示からすべての必須項目を真っ赤に染め上げるのは、ユーザービリティの観点から最悪だ。「お前はまだ何も書いていない!」と最初から怒られているようなプレッシャーをユーザーに与えてしまうからね。
解決策:`:user-invalid` や `:placeholder-shown` との組み合わせ
この問題をスマートに解決するために、現代のCSSではいくつかのアプローチがある。
1. 初期表示では色をつけず、ユーザーが操作(インタラクション)した後に光らせる
2. `:placeholder-shown` などをうまく利用して、未入力時の見た目をコントロールする
実務で最も堅牢なアプローチとして、ユーザーが一度フォーカスして離れた後(あるいは入力を試みた後)にスタイルを適用するパターンを見てみよう。
—
3. コピペで使える!洗練されたフォームスタイリングの実装例
よし、理屈はこれくらいにして、現場のプロダクションコードでそのまま使える実用的なCSSとHTMLのセットを置いておく。
そして、これが肝心のCSSだ。変数を使ってモダンに、かつアクセシビリティにも配慮したスタイルを組んでみる。
/ ==========================================
フォーム全体のエレガントなスタイリング
========================================== /
:root {
–color-primary: #0066cc;
–color-error: #d32f2f;
–color-border: #ccc;
–color-bg: #f9f9f9;
}
.c-form {
max-width: 480px;
margin: 2rem auto;
font-family: sans-serif;
}
.c-form__group {
margin-bottom: 1.5rem;
display: flex;
flex-direction: column;
}
.c-form__label {
font-weight: bold;
margin-bottom: 0.5rem;
font-size: 0.9rem;
}
/ 必須バッジのスタイリング /
.c-form__badge {
background-color: var(–color-error);
color: #fff;
font-size: 0.75rem;
padding: 0.1rem 0.4rem;
border-radius: 4px;
margin-left: 0.5rem;
vertical-align: middle;
}
.c-form__badge–optional {
background-color: #777;
}
/ インプット共通のスタイル /
.c-form__input {
padding: 0.75rem;
border: 1px solid var(–color-border);
border-radius: 6px;
font-size: 1rem;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
/ フォーカス時の挙動 /
.c-form__input:focus {
outline: none;
border-color: var(–color-primary);
box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.15);
}
/ エラーメッセージは初期状態では隠しておく /
.c-form__error-message {
display: none;
color: var(–color-error);
font-size: 0.8rem;
margin-top: 0.4rem;
}
/ ==========================================
:required とバリデーションの連携魔法
========================================== /
/
【ポイント】
:required 自体は「属性があるか」を見るだけなので、
ユーザーがまだ入力していない状態(かつプレースホルダーが表示されている状態)では
エラーカラーを出さないように :placeholder-shown を組み合わせるのがプロの技。
/
/ 必須かつ、未入力(placeholderが表示されている)かつ、フォーカスされていない場合 /
.c-form__input:required:placeholder-shown {
border-color: var(–color-border); / 普通のボーダーを維持 /
}
/
ユーザーが何かしら入力したが、バリデーションに違反している場合
(ネイティブの :invalid と :required を組み合わせる)
/
.c-form__input:required:not(:placeholder-shown):invalid {
border-color: var(–color-error);
background-color: rgba(211, 47, 47, 0.02);
}
/ バリデーションを通過した場合(正しい値が入力された) /
.c-form__input:required:not(:placeholder-shown):valid {
border-color: #2e7d32;
}
/ 不正な値が入っている時だけエラーメッセージを表示する /
.c-form__input:required:not(:placeholder-shown):invalid + .c-form__error-message {
display: block;
}
このコードの何が優れているのか?
1. JavaScriptを1行も書いていない:クラスの付け外しをJSで監視する必要が一切ない。ブラウザのレンダリングエンジンに任せているため、パフォーマンスが圧倒的に高い。
2. 初期表示でユーザーを威圧しない:`:placeholder-shown` を組み合わせることで、「ページを開いた直後なのに真っ赤」という最悪なUIアンチパターンを華麗に回避している。
3. アクセシビリティと直結している:HTMLの標準仕様(`required` とバリデーション状態)に完全準拠しているため、スクリーンリーダーなどの支援技術とも相性が良い。
—
4. シニアからの最後の小言
フロントエンドの開発現場では、「動的な制御はすべてJavaScriptでやるべきだ」という誤った万能感に囚われたエンジニアを時々見かける。だが、CSSでネイティブに解決できる機能をわざわざJSで重く実装するのは、百害あって一利なしだ。
ブラウザのネイティブ機能や疑似クラスは、長年かけてW3Cや各ブラウザベンダーが最適化し続けてきた「究極のパフォーマンス最適化の結晶」なんだよ。
`:required` は、正しく文脈を理解して使えば、あなたの書くフォームコードを劇的に美しく、そして軽量にしてくれる。ぜひ、明日からのプロジェクトでこの知見を活かしてみてくれ。コードレビューで後輩から「おっ、すげえ!」って言われること間違いなしだぜ。

コメント