【実務・中級編】 in-range疑似クラス – CSS実践ガイド

やあ、お疲れ様。
最近、社内のコードレビューをしていて、数値入力フォームのエラーハンドリングでJavaScriptの山のようなバリデーションロジックを見かけて、思わず「おや?」と思ったんだよね。もちろん複雑なビジネスロジックはJSに頼るべきだけど、ブラウザが標準で持ってくれている強力なネイティブ機能をドブに捨てるのは、フロントエンドエンジニアとしてちょっともったいない。

今回は、HTML5のバリデーションAPIの隠れた名優、`:in-range`疑似クラスについて深掘りしようか。
「名前は聞いたことあるけど、実務で使ったことないな」という中級クラスのキミにこそ、明日から即座にプロダクトへ導入できる実践知を授けよう。仕様の裏側から、現場でハマりがちな罠、そしてデザインシステムにどう組み込むかまで、徹底的に解説していくよ。

—

1. `:in-range` 疑似クラスとは何か?(基本仕様の整理)

まず前提として、この疑似クラスが何をターゲットにしているかのおさらいだ。
`:in-range` は、`` 要素(主に `type=”number”`, `type=”range”`, `type=”date”` などの数値系・日付系)に入力された値が、`min` 属性と `max` 属性で定義された範囲内に収まっている状態 のときにマッチする状態系の疑似クラスだ。

逆に、範囲外を叩いてしまった場合はお馴染みの `:out-of-range` が火を吹くわけだけど、今回は「正しく入力されているゾーン」をどうリッチに演出するか、というポジティブなアプローチに焦点を当てたい。

ブラウザの裏側の動き:なぜJSなしで動くのか?

「動的バリデーション=JavaScriptのイベントリスナー(`input` や `change`)監視」という刷り込みがフロントエンド界隈にはある。しかし、ブラウザのレンダリングエンジン(Blink, Gecko, WebKit)は、DOMツリーが構築された瞬間から、各インプット要素の `value`, `min`, `max` の数値を常に監視し、内部的なValidityState(妥当性フラグ)を計算している。

`:in-range` は、このブラウザのネイティブな状態管理と密接に連動している。
つまり、余計なJSのメインスレッドを一切汚染せず、CSSのレイヤーだけで超高速にスタイリングの切り替えが行われる。パフォーマンスの観点からも、使わない手はないんだよね。

—

2. 現場で即効性のある実用コード例

理屈はこれくらいにして、実際のコードを見せよう。
例えば、ECサイトの数量選択(Quantity Picker)や、ダッシュボードの数値設定モーダルを想像してほしい。ユーザーが許容範囲内の値を入力しているときは、安心感を与えるクリーンなUIを、範囲外のときには視覚的なフィードバックを即座に返す。

以下のコードをそのままエディタに貼って、ブラウザで挙動を確認してみてほしい。





:in-range Practical Demo





※ 1から10の範囲で入力してください。


このコードの美しいところは、JavaScriptを1行も書かずに、ユーザーが「1」から「10」の間で数字を変更しているリアルタイムな瞬間に、CSSだけでフォームの表情が切り替わるところだ。

—

3. 現場でハマりがちな「落とし穴」とベストプラクティス

さて、ここまで聞くと「最高じゃん、明日から全部これに置き換えよう!」と思うかもしれないが、シニアとして現場の泥臭い注意点も伝えておかないとね。いくつか重要な罠がある。

落とし穴1:初期状態で「空(empty)」のときどうなる?

ここ、一番やりがちなミスだ。
例えば `` と定義して、初期状態が空(値が何も入力されていない状態)のとき、ブラウザはこの要素を `:in-range` とみなすだろうか? それとも `:out-of-range` だろうか?

正解は「どちらにも該当しない」だ。
仕様上、値が空のインプットは範囲内・範囲外の判定対象外になる。したがって、ページ読み込み直後にいきなり緑色の「正常スタイル」が適用されてしまうことはない。ただし、ユーザーが一度「0」や「11」といった無効な値を入力し、その後フォームを空にした場合などはブラウザの実装によって挙動が揺らぐことがある。
そのため、必ず `:placeholder-shown` や `:invalid` などの疑似クラスと組み合わせて、状態の境界線を明確にデザイン設計する必要がある。

落とし穴2:`min` と `max` の属性が「必須」であることの意識

`:in-range` は、文字通り `min` または `max`(あるいはその両方)がHTML上に明示されている要素でなければ機能しない。
「CSSを書いたのに全然スタイルが当たらない!」と悩む後輩のコードを覗くと、大抵の場合はHTML側に `min`/`max` 属性が抜け落ちている。CSS単体で完結する魔法ではなく、HTMLのセマンティクスと強固に結合している仕様であることを忘れないでほしい。

設計上のベストプラクティス:デザインシステムへの組み込み

実務でコンポーネント指向の開発(ReactやVue、あるいはWeb Componentsなど)をしているなら、この `:in-range` は「フォームコントロールのプリミティブ層」に組み込むのが最も効果的だ。

例えば、CSS ModulesやTailwind CSS、あるいはVanilla Extractなどを使う場合でも、ネイティブの疑似クラスを活用することで、状態管理のボイラープレートコード(JS側の `useState` やバリデーション判定フラグ)を劇的に削減できる。
「JavaScriptはインタラクションの制御とデータの送信に集中させ、見た目のフィードバックはCSSのステート疑似クラスに任せる」
この役割分担こそが、モダンでスケーラブルなフロントエンドアーキテクチャの基本姿勢だ。

—

まとめ

`:in-range` 疑似クラス、どうだっただろうか?
派手なアニメーションをさせるような機能ではないけれど、こういう「ブラウザの標準機能をいかにエレガントにハックし、ユーザー体験(UX)の細部を磨き上げるか」という部分にこそ、中級からシニアへステップアップするためのエンジニアのセンスが宿る。

日々の実装の中で、つい面倒くさくてJSで状態をこねくり回してしまっている箇所があったら、「あ、これCSSの疑似クラスでいけるかも?」と一度立ち止まってみてほしい。
キミの書くコードが、より軽快で、よりモダンなものになるはずだ。

それじゃ、また次のコードレビュー会で!

コメント

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