フォームの入力欄に薄いグレーで表示されるプレースホルダーテキスト。デフォルトの見た目はブラウザ任せですが、CSSの::placeholder疑似要素を使えば色・フォントサイズ・字間など自由にカスタマイズできます。
この記事では、基本の色変更から:placeholder-shownを使ったフローティングラベル、フォーカス時アニメーション、ダークモード対応、アクセシビリティの注意点まで、placeholderのスタイリングに必要な知識をすべてまとめました。
::placeholder疑似要素でplaceholderの色・フォント・サイズを変更する方法、適用できるCSSプロパティの一覧、:placeholder-shown疑似クラスを使ったフローティングラベルの実装、フォーカス時のアニメーション、ダークモード対応、そしてplaceholderをラベル代わりに使ってはいけない理由まで解説します。
- ::placeholder 疑似要素の基本
- ::placeholder に適用できるCSSプロパティ一覧
- ブラウザごとのデフォルトplaceholderスタイル
- ::placeholder と :placeholder-shown の違い
- フォーカス時にplaceholderをフェードアウトさせる
- フローティングラベルの実装
- フォームバリデーションとの連携
- textarea の placeholder
- input type 別のplaceholder対応
- ダークモード対応
- Tailwind CSS での placeholder スタイリング
- アクセシビリティ: placeholderをラベル代わりにしてはいけない
- まとめ
- 関連記事
::placeholder 疑似要素の基本
::placeholderは、<input>や<textarea>のplaceholder属性で指定したテキストにスタイルを適用する疑似要素です。
/* placeholderの色を変更 */
::placeholder {
color: #94a3b8;
}
/* 特定の要素のplaceholderだけ変更 */
.search-input::placeholder {
color: #64748b;
font-style: italic;
}
ベンダープレフィックスはもう不要
かつては以下のようにブラウザごとのプレフィックスが必要でした。
/* 旧: ベンダープレフィックス付き(もう不要) */
::-webkit-input-placeholder { color: #999; } /* Chrome, Safari, Edge */
::-moz-placeholder { color: #999; } /* Firefox */
:-ms-input-placeholder { color: #999; } /* IE 10-11 */
/* 現在: これだけでOK */
::placeholder {
color: #999;
}
2025年現在、すべてのモダンブラウザ(Chrome, Firefox, Safari, Edge)が::placeholderをプレフィックスなしで対応済みです。IE対応が不要なプロジェクトでは、プレフィックスは書く必要がありません。
::placeholder に適用できるCSSプロパティ一覧
::placeholderはすべてのCSSプロパティに対応しているわけではありません。CSS仕様では::first-lineと同じプロパティセットが適用可能と定義されています。
| カテゴリ | プロパティ |
|---|---|
| フォント系 | font, font-size, font-weight, font-style, font-family, font-variant |
| テキスト色 | color, opacity |
| テキスト装飾 | text-decoration, text-transform, text-shadow |
| 間隔・行 | letter-spacing, word-spacing, line-height |
| 背景 | background, background-color, background-image 等 |
/* 様々なプロパティを活用した例 */
.styled-input::placeholder {
color: #94a3b8;
font-size: 13px;
font-style: italic;
letter-spacing: 0.5px;
text-transform: uppercase;
}
/* 注意: 以下のプロパティは ::placeholder には効かない */
/* padding, margin, display, width, height, border など */
ブラウザごとのデフォルトplaceholderスタイル
ブラウザによってplaceholderのデフォルトの見た目が微妙に異なります。
| ブラウザ | デフォルトの色 | 仕組み |
|---|---|---|
| Chrome / Edge | darkgray(#757575相当) | color: darkgray を直接指定 |
| Firefox | 半透明の黒 | 入力テキスト色に opacity: 0.54 を適用 |
| Safari | darkgray(#757575相当) | color: darkgray を直接指定 |
Firefoxはopacityで制御しているため、colorだけを変更しても意図した色にならないことがあります。確実にクロスブラウザで統一するにはcolorとopacity: 1の両方を指定しましょう。
/* クロスブラウザで確実に色を統一する */
::placeholder {
color: #94a3b8;
opacity: 1; /* Firefox のデフォルト opacity をリセット */
}
::placeholder と :placeholder-shown の違い
名前が似ていますが、役割がまったく異なる2つのセレクタです。
| セレクタ | 種類 | 対象 | 用途 |
|---|---|---|---|
::placeholder |
疑似要素 | placeholderテキスト自体 | 色・フォント等のスタイリング |
:placeholder-shown |
疑似クラス | input/textarea 要素自体 | 「placeholderが表示されている(= 未入力)」状態の検出 |
/* ::placeholder → テキストのスタイルを変える */
input::placeholder {
color: #94a3b8;
font-style: italic;
}
/* :placeholder-shown → 入力欄が空のときのスタイル */
input:placeholder-shown {
border-color: #e2e8f0; /* 未入力 → 薄いボーダー */
}
/* :not(:placeholder-shown) → 入力済みのとき */
input:not(:placeholder-shown) {
border-color: #3b82f6; /* 入力済み → 青いボーダー */
}
:placeholder-shownは「placeholderが表示されている = まだ何も入力されていない」ことを検出できるため、フローティングラベルやバリデーションで活躍します。
フォーカス時にplaceholderをフェードアウトさせる
入力欄にフォーカスしたときに、placeholderをふわっと消すアニメーションです。
/* フェードアウト */
input::placeholder {
color: #94a3b8;
opacity: 1;
transition: opacity 0.3s ease;
}
input:focus::placeholder {
opacity: 0;
}
スライドアップで消すパターン
/* フォーカスでplaceholderが上にスライドして消える */
input::placeholder {
color: #94a3b8;
transition: transform 0.3s ease, opacity 0.3s ease;
}
input:focus::placeholder {
transform: translateY(-100%);
opacity: 0;
}
フローティングラベルの実装
フローティングラベルは、未入力時にplaceholder風に表示し、入力開始時にラベルが上に移動するパターンです。CSSだけで実装できます。
<div class="float-label">
<input type="email" id="email" placeholder="メールアドレス" required>
<label for="email">メールアドレス</label>
</div>
.float-label {
position: relative;
}
.float-label input {
width: 100%;
padding: 16px 12px 8px;
border: 2px solid #e2e8f0;
border-radius: 8px;
font-size: 15px;
outline: none;
transition: border-color 0.2s;
}
/* placeholder は透明にする(:placeholder-shown の判定用に必要) */
.float-label input::placeholder {
color: transparent;
}
/* ラベルの初期位置(placeholder の位置に重ねる) */
.float-label label {
position: absolute;
left: 14px;
top: 50%;
transform: translateY(-50%);
color: #94a3b8;
font-size: 15px;
pointer-events: none;
transition: all 0.2s ease;
}
/* 入力済み or フォーカス時 → ラベルを上に移動 */
.float-label input:not(:placeholder-shown) + label,
.float-label input:focus + label {
top: 6px;
transform: translateY(0);
font-size: 11px;
color: #3b82f6;
}
.float-label input:focus {
border-color: #3b82f6;
}
user@example.com
仕組みのポイント
placeholder属性には空でない文字列を設定する必要がある(:placeholder-shownの判定に必須)::placeholder { color: transparent; }でplaceholder自体は見えなくする:not(:placeholder-shown)で「入力済み」を検出し、+ label(隣接兄弟セレクタ)でラベルのスタイルを変更- HTMLの順序は必ず input → labelの順にする(CSSの隣接兄弟セレクタは後方の要素しか選択できないため)
フォームバリデーションとの連携
:placeholder-shownを:valid/:invalidと組み合わせると、CSSだけでバリデーション表示が可能です。
/* 入力済み + バリデーションOK → 緑ボーダー */
input:not(:placeholder-shown):valid {
border-color: #22c55e;
}
/* 入力済み + バリデーションNG → 赤ボーダー */
input:not(:placeholder-shown):invalid {
border-color: #ef4444;
}
/* 未入力の required フィールドは :invalid だが、
:placeholder-shown で除外してスタイルを適用しない */
input:placeholder-shown:invalid {
border-color: #e2e8f0; /* 通常のボーダーのまま */
}
:placeholder-shownのおかげで、「まだ何も入力していないのにエラー表示」を防げるのがポイントです。required属性付きのフィールドは空の状態で:invalidですが、:placeholder-shownと組み合わせることで未入力時のエラー表示を抑制できます。
textarea の placeholder
<textarea>にも同様に::placeholderが使えます。
textarea::placeholder {
color: #94a3b8;
opacity: 1;
line-height: 1.6;
}
/* textarea のリサイズ時もplaceholderは自然に追従する */
textarea {
resize: vertical;
min-height: 120px;
}
textareaで複数行のplaceholderを表示
HTML属性内では改行できませんが、実体参照 を使うと改行が可能です。
<!-- 改行入りplaceholder -->
<textarea placeholder="1行目のテキスト 2行目のテキスト"></textarea>
ただし、この方法はブラウザによって挙動が異なる場合があります。確実に複数行のヒントテキストを表示したい場合は、placeholderではなく入力欄の下にヒントテキストを配置する方がアクセシビリティ的にも安全です。
input type 別のplaceholder対応
placeholder属性が使えるinput typeは限られています。
| input type | placeholder | 備考 |
|---|---|---|
text |
対応 | 最も一般的な使用 |
email |
対応 | 例: user@example.com |
password |
対応 | 例: 8文字以上の英数字 |
search |
対応 | Safariでのリセットが必要な場合あり |
tel |
対応 | 例: 090-1234-5678 |
url |
対応 | 例: https://example.com |
number |
対応 | 例: 0 |
date / time |
非対応 | ブラウザ独自のUIが表示される |
checkbox / radio |
非対応 | テキスト入力ではないため |
input[type=”search”] の注意点
Safari / WebKit ではinput[type="search"]に独自のスタイルが適用されるため、placeholderのカスタマイズが効かない場合があります。
/* Safari でsearch inputのスタイルをリセット */
input[type="search"] {
-webkit-appearance: none;
appearance: none;
}
input[type="search"]::placeholder {
color: #94a3b8;
}
ダークモード対応
ダークモードではplaceholderの色も調整が必要です。
/* ライトモード */
::placeholder {
color: #94a3b8;
opacity: 1;
}
/* ダークモード */
@media (prefers-color-scheme: dark) {
::placeholder {
color: #64748b;
}
}
/* CSS変数で管理するパターン */
:root {
--placeholder-color: #94a3b8;
}
@media (prefers-color-scheme: dark) {
:root {
--placeholder-color: #64748b;
}
}
::placeholder {
color: var(--placeholder-color);
opacity: 1;
}
Tailwind CSS での placeholder スタイリング
Tailwind CSS ではplaceholder:修飾子でplaceholderのスタイルを指定できます。
<!-- 基本的な色とスタイル -->
<input
type="text"
placeholder="検索..."
class="placeholder:text-gray-400 placeholder:italic placeholder:text-sm"
/>
<!-- フォーカス時にplaceholderの色を変更 -->
<input
type="email"
placeholder="メールアドレス"
class="placeholder:text-slate-400 focus:placeholder:text-slate-300"
/>
<!-- ダークモード対応 -->
<input
type="text"
placeholder="名前"
class="placeholder:text-gray-400 dark:placeholder:text-gray-600"
/>
よく使う Tailwind placeholder クラス
| クラス | CSS出力 |
|---|---|
placeholder:text-gray-400 |
::placeholder { color: #9ca3af; } |
placeholder:italic |
::placeholder { font-style: italic; } |
placeholder:text-sm |
::placeholder { font-size: 0.875rem; } |
placeholder:opacity-50 |
::placeholder { opacity: 0.5; } |
focus:placeholder:text-transparent |
:focus::placeholder { color: transparent; } |
アクセシビリティ: placeholderをラベル代わりにしてはいけない
placeholderはスタイリング以前に、使い方自体に注意が必要です。
placeholderの問題点
- 入力すると消える: ユーザーは何を入力すべきだったか忘れてしまう
- デフォルトの色がWCAGのコントラスト基準を満たさないことが多い(4.5:1未満)
- スクリーンリーダーによって読み上げられない場合がある(ブラウザ・AT依存)
- 翻訳ツールで翻訳されないことがある
- 入力済みの値と見間違えることがある(特に高齢者やロービジョンのユーザー)
正しいパターン
<!-- NG: placeholderだけでラベルを省略 -->
<input type="email" placeholder="メールアドレス">
<!-- OK: labelを使い、placeholderは入力例として使う -->
<label for="email">メールアドレス</label>
<input type="email" id="email" placeholder="例: user@example.com">
<!-- OK: フローティングラベル(視覚的にはplaceholder風、実装はlabel) -->
<div class="float-label">
<input type="email" id="email2" placeholder=" " required>
<label for="email2">メールアドレス</label>
</div>
placeholderは「入力例」や「ヒント」として使い、何を入力すべきかは必ず<label>で示すのがベストプラクティスです。
placeholderの色とコントラスト比
placeholderテキストもWCAG 2.1のコントラスト比基準を考慮してください。デフォルトの薄いグレーは基準を満たしていないことが多いです。
/* デフォルト(コントラスト不足の場合あり) */
::placeholder { color: #c0c0c0; } /* 白背景で 1.6:1 → NG */
/* WCAG AA 基準(4.5:1)を満たす色 */
::placeholder { color: #767676; } /* 白背景で 4.5:1 → OK */
/* ただし濃すぎると入力済みテキストと見間違えるため、
入力テキストの色より明確に薄くする */
input { color: #1e293b; } /* 入力テキスト: 濃い */
::placeholder { color: #94a3b8; } /* placeholder: 薄い */
まとめ
| やりたいこと | 使うもの |
|---|---|
| placeholderの色・フォントを変更 | ::placeholder { color: ...; } |
| Firefoxで色を確実に統一 | ::placeholder { opacity: 1; } を追加 |
| 入力済み/未入力で見た目を変える | :placeholder-shown / :not(:placeholder-shown) |
| フローティングラベルを実装 | :placeholder-shown + :not() + 隣接兄弟セレクタ |
| フォーカスでplaceholderを消す | input:focus::placeholder { opacity: 0; } |
| CSSだけでバリデーション表示 | :not(:placeholder-shown):valid / :invalid |
::placeholderは「見た目」を変えるだけのシンプルな疑似要素ですが、:placeholder-shownと組み合わせることでフローティングラベルやバリデーションといった高度なUI表現がCSSだけで実現できます。ただし、placeholderはラベルの代替ではないことを忘れずに。
