フロントエンドの現場で「おっ、これキレイに書けてるね」と後輩のコードを見て思わず唸らされる瞬間、それは大抵、CSSの細かい仕様や「痒い所に手が届く疑似クラス」を正しく使いこなしている時だ。
フォームのUI実装で、プレースホルダー(入力ヒント)が出ているかどうかでスタイルを変えたい、あるいは「何か文字が入力されるまで送信ボタンやラベルの見た目をコントロールしたい」と思ったことはないだろうか?
昔なら、JavaScriptの`input`イベントを監視して、`value`の長さを泥臭くチェックしてクラスを付け外ししていたはずだ。だが、今のモダンCSSには `:placeholder-shown` という強力な相棒がいる。こいつを使いこなせば、JSを1行も書かずに、ピュアなCSSだけで入力状態のスタイリングを完全にコントロールできる。
今回は、この `:placeholder-shown` の実務的なポテンシャルと、現場でスグに使える実践知を余すところなく伝授しよう。
—
1. `:placeholder-shown` とは何か?(標準仕様とブラウザの裏側)
まず大前提として、多くのエンジニアがここで誤解するポイントを訂正しておこう。
`:placeholder-shown` は、「プレースホルダーの文字そのもの」を選択する疑似クラスではない。
選択するのは、あくまで「現在、プレースホルダーが表示されている状態の `` や `だ。
ブラウザの裏側の動き
ブラウザは、要素の `value` プロパティが空(`””`)であり、かつ `placeholder` 属性が指定されている場合に、この `:placeholder-shown` という状態フラグを内部的にオンにする。
つまり、ユーザーが一文字でもキーボードから文字を入力した瞬間、`value` が空でなくなるため、ブラウザは瞬時にこのフラグをオフにする。この仕組みを利用することで、「入力前(プレースホルダー表示中)」と「入力後(実データ存在)」のDOMの状態を、CSSだけで綺麗にスイッチできるというわけだ。
—
2. 現場で即採用できる!Floating Label(フロートラベル)の実装例
実務で最もこの `:placeholder-shown` が真価を発揮するのが、いわゆる「フロートラベル(Material Designなどでよく見る、入力時にラベルがフワッと上に浮き上がるUI)」の実装だ。
かつてはJSが必須だったこのインタラクションを、HTMLとCSSだけで、しかもアクセシビリティを担保しながらスマートに構築してみよう。
コピペで動くHTML & CSS
/ フォーム全体のコンテナ /
.form-group {
position: relative;
margin-top: 1.5rem;
width: 100%;
max-width: 400px;
}
/ 入力フィールドの基本スタイル /
.form-input {
width: 100%;
padding: 1rem 0.75rem 0.5rem;
font-size: 1rem;
border: 1px solid #ccc;
border-radius: 4px;
outline: none;
background: transparent;
transition: border-color 0.2s ease;
}
.form-input:focus {
border-color: #2563eb;
}
/ ラベルのデフォルト位置(プレースホルダーが表示されている、つまり「未入力」の状態) /
.form-label {
position: absolute;
left: 0.75rem;
top: 50%;
transform: translateY(-50%);
font-size: 1rem;
color: #6b7280;
pointer-events: none; / ラベルがクリックを邪魔しないようにするお作法 /
transition: all 0.2s ease;
}
/
【核心】
inputが :placeholder-shown(=プレースホルダーが表示されている=未入力)のとき、
ラベルを中央(元の位置)に維持する。
/
.form-input:placeholder-shown ~ .form-label {
top: 50%;
font-size: 1rem;
color: #6b7280;
}
/
inputから :placeholder-shown が外れたとき(=文字が入力されたとき)、
あるいは focus されたときに、ラベルを上にスライドさせる。
/
.form-input:not(:placeholder-shown) ~ .form-label,
.form-input:focus ~ .form-label {
top: 0.2rem;
font-size: 0.75rem;
color: #2563eb;
background-color: #fff;
padding: 0 0.25rem;
}
> 💡 シニアからのワンポイントアドバイス:
> HTML側で `placeholder=” “` と、あえて半角スペースを1文字入れている点に注目してほしい。
> これをサボって `placeholder` 属性自体を省略してしまうと、ブラウザによっては `:placeholder-shown` が正しく発火しない原因になる。プレースホルダーとしての文字は見せたくないが、このCSSトリックを使いたい時は、必ず空スペース(あるいは不可視文字)を仕込むのが現場のハックだ。
—
3. 応用編:未入力バリデーションの視覚化
もう一つの実務的なユースケースとして、「必須入力項目が空のまま、ユーザーがフォームからフォーカスを外した(あるいは送信しようとした)時のスタイリング」がある。
これも `:placeholder-shown` と `:user-invalid`(または `:invalid`)を組み合わせることで、JSの介入なしにエレガントに実装できる。
/
ユーザーが一度触ったあと、かつ入力内容が空(placeholderが表示されている)の場合に
枠線を赤くして注意を促す
/
.form-input:user-invalid:not(:placeholder-shown) {
border-color: #dc2626;
}
このように、「プレースホルダーが見えている状態なのか、そうでないのか」をCSSの条件分岐の軸に据えることで、UIの状態管理が劇的にシンプルになる。
—
まとめ:CSSをもっと「ロジカル」に使おう
僕たちが書くCSSは、単に「見た目を綺麗に飾るためのコード」ではなくなりつつある。DOMの状態を正確に捉え、ブラウザのエンジンと対話しながらインタラクティブな挙動を実現する、立派な「ロジックの記述言語」だ。
今回紹介した `:placeholder-shown` は、その代表格と言える。
「面倒なことは全部JSにやらせよう」という思考から脱却し、「CSSでやれることはCSSに任せる」というアプローチをとることで、コードベースは軽くなり、パフォーマンスも向上し、何より保守性の高いクリーンなフロントエンドが実現できる。
次の案件のフォーム実装では、ぜひこの `:placeholder-shown` をしれっと導入して、周りのメンバーを「おっ」と言わせてみてほしい。

コメント