- 技術 💻
プレースホルダーとは|入力欄・テンプレート・SQL・画像の4つの意味と使い方
結論
プレースホルダー(placeholder)とは、「あとから本当の値が入る場所に、仮に置いておく文字や領域」のことです。IT では主に4つの場面で使われ、HTML の入力欄の薄い文字、文字列テンプレートの {name}、SQL のバインド変数(?・:name)、画像を読み込むまでの仮の領域を指します。
この記事でわかること
- 4つの意味の見分け方と、HTML の placeholder 属性の書き方・使える要素
- Chromium で計測した既定色のコントラスト比(白背景 4.61:1、暗い背景 3.62:1)と label との違い
- 各言語のテンプレート・SQLite のバインド変数・画像の CLS をすべて実行した結果
「プレースホルダー」は、英語の place(場所)+ holder(確保するもの)で、「場所取り」という意味です。どの場面でも考え方は同じで、本当の値はあとから入る、それまでの仮のものを指します。
flowchart LR
P["プレースホルダー<br>あとから入る値の<br>仮の場所"] --> A["入力欄の薄い文字<br>HTML の placeholder 属性"]
P --> B["文字列の穴<br>name の印・%s・$1"]
P --> C["SQL のバインド変数<br>? と :name"]
P --> D["画像・部品の仮の領域<br>スケルトン・サイズ確保"]
よく調べられることの答えを先にまとめます。
| 知りたいこと | 答え | 詳しい節 |
|---|---|---|
| プレースホルダーとは | あとから入る値の代わりに、仮に置いておく文字や場所 | プレースホルダーとは |
| placeholder html の書き方 | <input placeholder="例:山田 太郎">。text・email など7種と textarea |
HTML の placeholder 属性 |
| 入力すると消える | 値が空のときだけ表示。送信される値には含まれない | 入力を始めると消える |
| 色を変えたい(CSS) | input::placeholder { color: #767676; }。4.5:1 以上に |
::placeholder の既定色 |
| label との違い | label は常に見え、読み上げられ、クリックで欄に移る | placeholder と label の違い |
| プログラミングのプレースホルダー | {name}・%s・${name} に値を差し込む |
文字列テンプレート |
| SQL の ? や :name | バインド変数。値は値として扱われ、SQL として解釈されない | SQL のプレースホルダー |
| 画像のプレースホルダー | width/height か aspect-ratio で領域を確保すると CLS が 0 になる | 画像のプレースホルダーと CLS |
| PowerPoint のプレースホルダー | レイアウトに置かれた、書式つきの入力枠 | PowerPoint・Word・OneDrive |
確認環境:Ubuntu 24.04.5 LTS の上で、HTML の挙動は Chromium 153.0.8010.12(Chrome for Testing。playwright 1.63.0 から headless で起動)で、127.0.0.1:45106 に立てた自作の HTTP サーバー(Python http.server)のページを開いて計測しました。::placeholder の色は getComputedStyle(要素, '::placeholder') と、入力欄のスクリーンショットの画素値の両方で確かめ、コントラスト比は WCAG の相対輝度の式で計算しています。アクセシビリティツリーは playwright の aria_snapshot()、CLS は PerformanceObserver(layout-shift)で、1.5秒遅れて返る画像を置いたページを幅 400px で開いて計測しました。文字列テンプレートは Python 3.13.18・Node.js 22.23.4・OpenJDK 21.0.12.1・Go 1.24.7・PHP 8.3.6・Ruby 3.3.6・gcc 13.3.0・bash で、SQL のバインド変数は Python の sqlite3(SQLite 3.53.1)・PHP の PDO・Node.js の node:sqlite で実行しました。placeholder 属性と ::placeholder の定義は MDN と WHATWG の HTML 仕様、Chromium の既定色は Chromium のソースコード(html.css)、コントラストの基準は WCAG 2.2 の達成基準 1.4.3、CLS の定義は web.dev、PowerPoint と OneDrive の意味は Microsoft の公式ページで確かめました。図は mermaid 11.16.0 で描画を確かめています(確認日 2026年10月29日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「プレースホルダーとは|入力欄・テンプレート・SQL・画像の4つの意味と使い方」
プレースホルダーとは(4つの意味の見分け方)
この節では、「プレースホルダー」という言葉が IT のどの場面で何を指すのかと、見分け方が分かります。
プレースホルダーとは、本当の値があとから入る場所を、仮の文字や領域で確保しておくものです。 共通するのは「仮であること」「本物が入ると役目を終えること」の2点で、場面によって指すものが変わります。
| 場面 | プレースホルダーが指すもの | 本物が入ると |
|---|---|---|
| HTML の入力欄 | 値が空のときに薄く表示される「例:山田 太郎」などの文字 | 文字を打ち始めると消える |
| 文字列テンプレート | {name}・%s・${name} のような「穴」 |
実行時に値で置き換わる |
| SQL(バインド変数) | ?・:name・$1 のような値の置き場 |
実行時に値が結び付けられる |
| 画像・画面の部品 | 読み込み中に表示する灰色の枠やぼかし画像(スケルトン) | 本物の画像に置き換わる |
| PowerPoint・Word | 「クリックしてタイトルを入力」と書かれた入力枠 | 入力した内容だけが表示・印刷される |
| OneDrive などのクラウドの同期 | 中身をまだダウンロードしていないファイルの仮の実体 | 開くと中身が取得される |
検索で「プレースホルダー」と調べる人の多くは、1つ目のHTML の入力欄の意味を探しています。この記事も、入力欄の話を中心に、残りの意味を順に扱います。
入力欄の薄い文字
HTML の placeholder 属性。フォームの入力例やヒントを、欄の中に薄い色で出す。
Web 制作・UI デザイン
文字列の穴
「{name}さん」の {name}。実行時に値を差し込む。メールの文面や翻訳ファイルにも使う。
プログラミング全般
SQL のバインド変数
WHERE name = ? の ?。値を SQL と分けて渡す仕組みで、安全に扱える。
データベース
仮の領域
画像が届くまでの灰色の枠。領域を先に確保して、画面のガタつき(CLS)を防ぐ。
表示速度・UX
HTMLのplaceholder属性とは(書き方と使える要素)
この節では、HTML の placeholder 属性の書き方と、どの要素・どの type で表示されるのかが、Chromium で確かめた結果で分かります。
placeholder 属性は、フォーム部品の値が空のときに、欄の中に表示する短いヒントを指定します。 MDN は「プレースホルダーテキストは、ユーザーにコントロールに入力するべきデータの種類に関する短いヒントを提供するべきです」とし、「説明や質問ではなく、期待するデータの種類のヒントとなる単語や短いフレーズ」が効果的だと説明しています。
<label for="name">名前</label>
<input id="name" name="name" type="text" placeholder="例:山田 太郎">
<label for="mail">メールアドレス</label>
<input id="mail" name="mail" type="email" placeholder="例:taro@example.com">
<label for="memo">備考</label>
<textarea id="memo" name="memo" placeholder="例:平日の午後が連絡しやすいです"></textarea>
MDN によると、placeholder 属性が使えるのは text・search・url・tel・email・password の input と textarea です。WHATWG の仕様の一覧では number も対象に含まれています。手元の Chromium で、type ごとに「プレースホルダーが表示されているか」を :placeholder-shown 擬似クラスで確かめました。
| 要素・type | :placeholder-shown | 手元の表示 |
|---|---|---|
| input type="text" | true | 薄い文字で表示 |
| input type="email" | true | 薄い文字で表示 |
| input type="number" | true | 薄い文字で表示(Chromium) |
| input type="date" | false | 表示されない(年/月/日 の入力部品が出る) |
| textarea | true | 薄い文字で表示。改行( )も2行で表示 |
| input に改行を入れた | true | 改行は無視され「1行目2行目」と1行で表示 |
- type="date" や type="checkbox" には表示されません。 日付の入力例を出したいときは、欄の外に「例:2026/10/29」と書きます。
- MDN は、placeholder に改行(LF・CR)を含めるとクリップされる、としています。手元でも input では改行が無視され、textarea では2行で表示されました。
- HTML の input の種類ごとの値の形式は、関連記事「HTML input type 一覧|全22種の用途・値の形式・検証結果の早見表」で扱っています。
入力を始めると消える(:placeholder-shownと送信される値)
この節では、プレースホルダーがいつ消えていつ戻るのか、そしてフォームを送ったときに何が送られるのかが分かります。
プレースホルダーは「値が空のとき」だけ表示され、1文字でも入力すると消えます。消しても戻ります。 手元の Chromium で、入力の前後に :placeholder-shown が一致するかを見ました。
読み込み直後 #a.matches(':placeholder-shown') = true
「鈴木」と入力 #a.matches(':placeholder-shown') = false value = 鈴木
値を空に戻す #a.matches(':placeholder-shown') = true
次に、何も入力せずに送信したときに、サーバーに届いた本文の原文です。プレースホルダーの文字は1つも送られていません。
POST /submit
Content-Type: application/x-www-form-urlencoded
name=&mail=&c=&d=&e=&e2=&g=&n=&dt=&nl=&ta=&fl=
「プレースホルダーに書いた例の値が、そのまま登録されてしまった」という不具合は起きません。逆に、プレースホルダーを「初期値」のつもりで使うと、何も送られません。初期値にしたいときは value 属性を使います。
placeholder と value の違い
見分ける問い:「このまま送られてよい値か」
:placeholder-shown は CSS からも JavaScript からも使えます。「未入力の欄の数」は document.querySelectorAll(':placeholder-shown').length で数えられ、未入力の欄の枠線だけ色を変える、といった使い方もできます。
::placeholderの既定色とコントラスト比(Chromiumで計測)
この節では、プレースホルダーの既定の色が何色で、背景とのコントラスト比がいくつなのか、CSS で変えるときに何色にすればよいかが、計測した数値で分かります。
手元の Chromium 153 では、プレースホルダーの既定の色は rgb(117, 117, 117)(#757575)で、白い背景とのコントラスト比は 4.61:1 でした。 これは WCAG 2.2 の達成基準 1.4.3(最低限のコントラスト。通常の文字は 4.5:1 以上)を満たします。Chromium のソースコード(html.css)でも ::-webkit-input-placeholder { color: #757575; } と書かれています。MDN には「Chrome は darkgray を使う」とありますが、darkgray(#a9a9a9)なら 2.35:1 で基準に届きません。手元の版では #757575 でした。
WCAG の達成基準 1.4.3 の解説(Understanding SC 1.4.3)は、この達成基準はプレースホルダーの文字にも適用される(This success criterion applies to text in the page, including placeholder text)と明記しています。計測した結果です。
| 指定 | 計算された色 | 背景 | コントラスト比 | 4.5:1 |
|---|---|---|---|---|
| 既定(指定なし) | rgb(117,117,117) | 白 | 4.61:1 | 満たす |
| 既定・暗い背景 #1e1e1e | rgb(117,117,117) | rgb(30,30,30) | 3.62:1 | 満たさない |
| 既定・color-scheme: dark | rgb(117,117,117) | rgb(59,59,59) | 2.43:1 | 満たさない |
color: #999 |
rgb(153,153,153) | 白 | 2.85:1 | 満たさない |
color: #767676 |
rgb(118,118,118) | 白 | 4.54:1 | 満たす |
color: currentColor |
rgb(34,34,34) | 白 | 15.91:1 | 満たす(本文と区別しにくい) |
color-mix(in srgb, currentColor 70%, transparent) |
本文色 70%(白と混ぜて約 rgb(100,100,100)) | 白 | 5.92:1 | 満たす |
スクリーンショットの画素も確かめました。既定のプレースホルダーを描いた入力欄で、いちばん暗い画素は (117, 117, 117) で、計算された色と一致しています(Chromium の既定では opacity は 1 でした。MDN によると Firefox は不透明度 54% で描くため、ブラウザごとに見え方が違います)。
/* 白い背景:4.5:1 を満たしつつ本文より薄く */
input::placeholder,
textarea::placeholder {
color: #767676; /* 4.54:1 */
opacity: 1; /* Firefox の半透明を打ち消す */
}
/* 暗い背景(本文が #eee のとき) */
.dark input::placeholder {
color: #a0a0a0; /* #1e1e1e に対して約 6.4:1 */
}
Windows の「ハイコントラストモード」(forced-colors)を Chromium で模擬すると、プレースホルダーの色は rgb(96, 0, 0)、本文は rgb(0, 0, 0) と、システムの色に置き換わりました。MDN が注意しているとおり、このモードではプレースホルダーと入力済みの文字の見分けがつきにくくなります。色だけで「まだ入力していない」を伝える設計は避けます。
1薄くしすぎない
#999・#aaa・#ccc は白背景で 4.5:1 を下回る。#767676 より濃い色にする。
2濃くしすぎない
本文と同じ色にすると、入力済みの値と見間違える。本文より薄く、基準より濃く、の間に置く。
3ダークモードは別に決める
既定色のままでは暗い背景で 3.62:1 だった。prefers-color-scheme: dark で色を指定し直す。
placeholderとlabelの違い(アクセシビリティツリーで確認)
この節では、「label の代わりに placeholder を使う」と何が起きるのかが、Chromium のアクセシビリティツリーとクリックの挙動で分かります。
label は「この欄が何か」を示す名前で、placeholder は「入力例」です。役割が違います。 MDN は「プレースホルダーを <label> のかわりに用いてはいけません」とし、理由として、値が入ると見えなくなること、スクリーンリーダーは既定ではプレースホルダーを読み上げないことを挙げています。
手元で、label がある欄と、placeholder だけの欄のアクセシビリティツリー(支援技術が受け取る情報)を取りました。
label あり(<label for="a">名前</label> + placeholder="例:山田 太郎")
- textbox "名前":
- /placeholder: 例:山田 太郎
placeholder だけ(<input type="email" placeholder="メールアドレス">)
- textbox "メールアドレス"
Chromium は、label が無いときの代替として placeholder を欄の名前に使っていました。ただし、これはブラウザが補っている動きであり、入力して placeholder が消えたあとに名前が残るかは支援技術しだいです。label があれば、名前(名前)と入力例(例:山田 太郎)が別々に伝わります。
| 観点 | label | placeholder |
|---|---|---|
| 入力中も見えるか | 見える | 消える(手元で確認) |
| クリックすると | 欄にフォーカスが移る(手元で確認:activeElement = a) | 欄をクリックしたのと同じ |
| 支援技術への伝わり方 | 欄の名前として伝わる | 既定では読まれないことがある(MDN) |
| コントラスト | 本文と同じ色にできる | 薄い色が既定。基準を下回りやすい |
| 向いている内容 | 項目名(名前・メールアドレス) | 入力例(例:山田 太郎) |
label を置けないデザインのときは、aria-label か、見えない label(visually-hidden)で名前を付け、入力例は欄の外に aria-describedby で結び付けます。MDN が示している形です。
<label for="user-email">メールアドレス</label>
<span id="user-email-hint">例:jane@sample.com</span>
<input id="user-email" name="email" type="email"
aria-describedby="user-email-hint">
WCAG の項目ごとの確かめ方は、関連記事「WCAG 2.2チェックリスト|A・AA全55項目と確認方法・axe検査手順」で扱っています。
フローティングラベルの作り方(:placeholder-shownで動かす)
この節では、「欄の中にラベルがあり、入力を始めると上に小さく移る」フローティングラベルを、JavaScript なしで作る方法と、動いた結果が分かります。
フローティングラベルは、label を欄の上に重ねて置き、:placeholder-shown が外れたら(値が入ったら)label を上へ移す CSS で作れます。 placeholder 属性は空白1文字(" ")にして、「表示はしないが :placeholder-shown は効く」状態にするのがコツです。
<p class="fl">
<input id="company" name="company" type="text" placeholder=" ">
<label for="company">会社名</label>
</p>
.fl { position: relative; display: inline-block; margin-top: 18px; }
.fl input { width: 260px; font-size: 16px; padding: 6px; }
.fl label {
position: absolute; left: 8px; top: 7px;
color: #666; font-size: 16px; background: #fff; padding: 0 2px;
transition: all .12s; pointer-events: none;
}
.fl input:focus + label,
.fl input:not(:placeholder-shown) + label {
top: -10px; font-size: 12px; color: #0b57d0;
}
Chromium で label の位置(入力欄の上端からの距離)と文字の大きさを、状態ごとに取りました。
| 状態 | label の位置 | 文字の大きさ | 色 |
|---|---|---|---|
| 読み込み直後(空・フォーカスなし) | 欄の上端から +7px(欄の中) | 16px | rgb(102,102,102) |
| フォーカスした | -10px(欄の上) | 12px | rgb(11,87,208) |
| 「RJC」と入力してフォーカスを外した | -10px(上に残る) | 12px | rgb(11,87,208) |
| 値を消してフォーカスを外した | +7px(欄の中に戻る) | 16px | rgb(102,102,102) |
アクセシビリティツリーでは、この欄は textbox "会社名" と、label の名前がそのまま付いていました。見た目は placeholder のようでも、中身は本物の label なので、入力中も名前が残ります。label の色 rgb(102,102,102) は白背景で 5.74:1 です。
placeholder=" "(空白1文字)を忘れると、:placeholder-shownが一致せず、最初から label が上に行ったままになります。- ブラウザの自動入力(オートフィル)で値が入ったときも
:placeholder-shownが外れるため、label は上に移ります。 - 入力例(例:山田 太郎)を同時に出したいときは、フローティングラベルの下に小さな文字で置きます。欄の中に2つ入れると読めません。
プレースホルダーの正しい使い方と使わない判断
この節では、プレースホルダーを使ってよい場面と、使わないほうがよい場面の線引きが分かります。
プレースホルダーは「無くても入力できるが、あると迷いにくい」補助に限って使います。 無いと入力できない情報(項目名・必須の形式・制約)は、消えない場所(label・欄の外の説明)に書きます。
- 1項目名は label に書く「名前」「メールアドレス」を placeholder だけにしない
- 2形式の決まりは欄の外に書く「ハイフンなし」「8文字以上」は消えると困る
- 3入力例だけを placeholder に書く「例:」を付けて、入力済みの値と区別する
- 4短く、欄に収まる長さにする収まらない分は切れて見えない(下の実測)
- 5色は 4.5:1 以上、本文より薄く#767676 以上の濃さ。ダークモードは別に決める
長い placeholder は切れる(実測)
幅 220px(文字 16px)の欄に、27文字の placeholder「例:半角英数字8文字以上。大文字と記号を1つ以上含める」を入れました。文字の幅を measureText で測ると 420px で、欄の内側 204px に収まるのは 13文字(「例:半角英数字8文字以上。」)まででした。残りの「大文字と記号を1つ以上含める」は見えません。スクロールもできません。
| 使う場面 | 判断 | 理由 |
|---|---|---|
| 検索ボックス(欄が1つ) | 使う | 何の欄か明らかで、入力例が役に立つ |
| 氏名の「例:山田 太郎」 | 使う(label と併用) | 姓名の順や全角半角の例になる |
| 項目名の代わり | 使わない | 入力すると何の欄か分からなくなる |
| パスワードの条件(8文字以上など) | 使わない | 消えると条件を確かめられない。長くて切れる |
| 電話番号のハイフンの有無 | 使わない | 形式の決まりは欄の外に。できれば両方受け付ける |
| type="date" の入力例 | 使えない | 表示されない(手元で確認) |
| 登録済みの値の表示 | 使わない | value 属性を使う。placeholder は送信されない |
フォーム部品の見た目の整え方は、関連記事「CSSフォームデザイン|input・select・チェックボックス装飾」で扱っています。
プログラミングのプレースホルダー:文字列テンプレートの実行例
この節では、プログラミングで「プレースホルダー」と呼ばれる、文字列の中の穴({name}・%s・${name})の書き方が、主な言語の実行結果で分かります。
文字列テンプレートのプレースホルダーは、文字列の中に置いた「あとで値を入れる印」です。 言語ごとに記号は違いますが、「印を書く → 値を渡す → 置き換わる」の流れは同じです。同じ文「山田さん、3点で1,234円です」を各言語で作りました。
| 言語 | プレースホルダーの書き方 | 手元の実行結果 |
|---|---|---|
| Python | f"{name}さん、{n}点で{price:,.0f}円"・"{}".format()・"%s" %・Template("$name") |
山田さん、3点で1,234円です |
| JavaScript | `${name}さん、${n}点`(テンプレートリテラル)・console.log("%s", name) |
山田さん、3点で1,234.5円です |
| Java | String.format("%sさん、%d点で%,.0f円")・MessageFormat.format("{0}さん、{1}点")・"%s".formatted() |
山田さん、3点で1,235円です |
| Go | fmt.Printf("%sさん、%d点で%.0f円")・%v |
山田さん、3点で1234円です |
| PHP | sprintf("%sさん、%d点")・"{$name}さん"・strtr("{name}さん", [...]) |
山田さん、3点で1,235です |
| Ruby | "#{name}さん"・format("%sさん")・"%{name}さん" % {name: ...} |
山田さん、3点で1235円です |
| C | printf("%sさん、%d点で%.0f円\n", name, n, price) |
山田さん、3点で1234円です |
| bash | printf '%sさん、%d点\n' "$name" "$n"・"${name}さん" |
山田さん、3点 |
Python の例と実行結果です。
name, n, price = "山田", 3, 1234.5
print(f"{name}さん、{n}点で{price:,.0f}円です") # f文字列
print("{}さん、{}点で{:,.0f}円です".format(name, n, price)) # str.format
print("{name}さん、{n}点".format(name=name, n=n)) # 名前つき
print("%sさん、%d点で%.1f円です" % (name, n, price)) # % 書式
from string import Template
print(Template("$nameさん、${n}点").substitute(name=name, n=n))
山田さん、3点で1,234円です
山田さん、3点で1,234円です
山田さん、3点
山田さん、3点で1234.5円です
山田さん、3点
1234.5 の丸めが言語で違う点にも気づきます。Python・Go・C の %.0f は「1234」(偶数への丸め)、Java の %,.0f と PHP の number_format・Ruby の round は「1235」でした。金額を出すときは、言語の丸め方を確かめます。
値が足りないときのエラー原文
プレースホルダーの数と渡した値の数が合わないときの、各言語の反応です。言語によって「エラーになる」「そのまま出す」が分かれます。
Python : KeyError: 'age' ({age} に値を渡していない)
Python : TypeError: not enough arguments for format string (%d に値が無い)
Java : java.util.MissingFormatArgumentException: Format specifier '%d'
Go : 山田さん、%!d(MISSING)点 (エラーにならず、印が残る)
PHP : Fatal error: Uncaught ArgumentCountError: 3 arguments are required, 2 given
Ruby : KeyError: key{age} not found
JS : ReferenceError: undefinedVar is not defined (${} の中の変数が無い)
C(gcc) : warning: format '%d' expects argument of type 'int', but argument 2 has type 'char *' [-Wformat=]
Go は実行時にエラーにならず、%!d(MISSING) という印が出力にそのまま残ります。テストの出力やログにこの文字列が無いかを探すと、埋め忘れを見つけられます。Python の f文字列の書式指定は、関連記事「Python f-string書式指定|全項目の早見表と実行結果・3.14対応」で扱っています。
位置で指定する
%s・{}・{0}・$1
短い。順番を間違えると気づきにくい
同じ値を2回使うには {0} のような番号が要る
名前で指定する
{name}・${name}・%(name)s・:name
読みやすい。翻訳ファイルやメールの文面に向く
名前の綴りを間違えると KeyError になる
SQLのプレースホルダー(バインド変数)をSQLiteで実行
この節では、SQL の ? や :name が何をしているのか、文字列を連結した場合と何が違うのかが、SQLite で実行した結果で分かります。
SQL のプレースホルダー(バインド変数・パラメーター)は、SQL 文と値を分けて渡す仕組みです。 SQL 文の中に ? や :name を書き、値は別の引数で渡します。データベースは SQL 文を先に解釈し、あとから値を「値として」結び付けるため、値の中に引用符や SQL の語が入っていても、SQL の構造は変わりません。Python の sqlite3 の公式ドキュメントも、SQL インジェクション攻撃を避けるために、文字列フォーマットの代わりに常にプレースホルダーを使うよう求めています。
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE users(id INTEGER PRIMARY KEY, name TEXT, age INTEGER)")
con.executemany("INSERT INTO users(name, age) VALUES (?, ?)",
[("山田", 30), ("O'Brien", 41), ("1 OR 1=1", 25)])
name = "O'Brien"
# 1) 文字列の連結:引用符で SQL が壊れる
try:
con.execute("SELECT id, name FROM users WHERE name = '" + name + "'")
except sqlite3.OperationalError as e:
print("連結:", e)
# 2) ? プレースホルダー(qmark)
print("? :", con.execute("SELECT id, name FROM users WHERE name = ?", (name,)).fetchall())
# 3) :name プレースホルダー(named)
print(":n :", con.execute("SELECT id, name FROM users WHERE name = :n", {"n": name}).fetchall())
# 4) 値は「値」として扱われ、SQL として解釈されない
print("値 :", con.execute("SELECT id, name FROM users WHERE name = ?", ("1 OR 1=1",)).fetchall())
連結: near "Brien": syntax error
? : [(2, "O'Brien")]
:n : [(2, "O'Brien")]
値 : [(3, '1 OR 1=1')]
読み方です。
- 連結:名前に含まれる
'が SQL の引用符として解釈され、near "Brien": syntax errorで失敗しました。名前に引用符が入る人(O'Brien さん)は珍しくありません。 - ? と :name:同じ名前で、正しく1行が返りました。引用符をエスケープする処理は書いていません。
- 値:
1 OR 1=1という文字列を渡しても、その文字列と一致する行(id 3)だけが返り、「全部の行」にはなりません。値は SQL の一部ではなく、値のままです。
同じことを PHP(PDO)と Node.js(node:sqlite)でも実行しました。書き方は違っても、値の渡し方は同じです。
$st = $pdo->prepare("SELECT id, name FROM users WHERE name = :name");
$st->execute([":name" => "O'Brien"]);
print_r($st->fetch(PDO::FETCH_ASSOC)); // Array ( [id] => 1 [name] => O'Brien )
import { DatabaseSync } from "node:sqlite";
const db = new DatabaseSync(":memory:");
db.prepare("SELECT id, name FROM users WHERE name = ?").all("O'Brien");
db.prepare("SELECT id, name FROM users WHERE name = $name").get({ $name: "O'Brien" });
// [ { id: 1, name: "O'Brien" } ] / { id: 1, name: "O'Brien" }
プレースホルダーが使えない場所
プレースホルダーに入れられるのは値だけです。表名・列名・ORDER BY の並び順には使えません。手元のエラー原文です。
con.execute("SELECT * FROM ? WHERE id = 1", ("users",))
→ sqlite3.OperationalError: near "?": syntax error
表名や列名を動的に変えたいときは、許可した名前の一覧(許可リスト)と照合してから SQL 文に組み立てます。LIKE の % は値の側に付けます(WHERE name LIKE ? に "%田%" を渡すと「山田」が返りました)。
連結した SQL と直した SQL を並べた比較は、関連記事「SQLインジェクション対策|脆弱なコードと修正版を実行して比較」で扱っています。
データベース・言語ごとのプレースホルダーの書き方
この節では、「? なのか %s なのか $1 なのか」が、データベースとライブラリの組み合わせでどう決まるのかが分かります。
記号はデータベースではなく、使うライブラリ(ドライバー)が決めます。 Python の DB-API(PEP 249)は、ライブラリが paramstyle で自分の記号を宣言する決まりになっています。
| paramstyle(PEP 249) | 書き方 | 主な例 |
|---|---|---|
| qmark | WHERE name = ? |
sqlite3(手元で確認)・JDBC・ODBC |
| numeric | WHERE name = :1 |
Oracle 系のライブラリ |
| named | WHERE name = :name |
sqlite3(手元で確認)・Oracle 系 |
| format | WHERE name = %s |
psycopg(PostgreSQL)・MySQL 系のライブラリ |
| pyformat | WHERE name = %(name)s |
psycopg(PostgreSQL) |
- psycopg の
%sは Python の文字列書式ではありません。 psycopg 3 の公式ドキュメントは「%や+で値をクエリに結合してはいけない」と書き、クエリとパラメーターは別々にサーバーへ送られる、と説明しています。見た目が同じでも、"..." % (値,)と書いた瞬間に文字列の連結になります。 - PostgreSQL のサーバー側(
PREPARE文)では、パラメーターは$1・$2と位置で参照します(公式ドキュメント)。Node.js の pg ライブラリもこの形です。 - Java の JDBC(PreparedStatement)は
?だけで、名前付きは Spring の NamedParameterJdbcTemplate などライブラリ側が:nameを?に変換します。
- 1値は必ず第2引数で渡すf文字列・format・+ で SQL に埋め込まない。見た目が %s でも同じ
- 2値が1つでもタプル・リストにするsqlite3 に文字列をそのまま渡すと、文字数ぶんの値と数えられる(下のエラー表)
- 3表名・列名・ORDER BY には使わないnear "?": syntax error になる。許可リストで組み立てる
- 4ライブラリの paramstyle を確かめるsqlite3 は ? と :name、psycopg は %s と %(name)s
画像のプレースホルダーとCLS(レイアウトのずれ)の実測
この節では、画像が届くまでの「仮の領域」を用意すると、画面のガタつき(CLS)がどれだけ減るのかが、Chromium で計測した数値で分かります。
画像のプレースホルダーとは、画像を読み込む前に、同じ大きさの領域を確保しておくことです。 領域が無いと、画像が届いた瞬間に下の文章が押し下げられます。この「予期しないずれ」を数値にしたのが CLS(Cumulative Layout Shift)で、web.dev は 0.1 以下を「良好」、0.25 を超えると「不良」としています。
1.5秒遅れて返る 800×450 の画像を、見出しと本文の間に置いたページを5通り作り、幅 400px の Chromium で開きました。
| 画像の書き方 | CLS | 下の見出しの移動 |
|---|---|---|
<img src="…">(大きさの指定なし) |
0.0513 | 188px 下へ |
<img width="800" height="450"> + height:auto |
0 | 0px |
CSS aspect-ratio: 16/9 + 灰色の背景 |
0 | 0px |
| スケルトン(アニメーションする灰色の枠に重ねる) | 0 | 0px |
| width/height + 16×9 の小さな画像を背景に(LQIP) | 0 | 0px |
いちばん手軽なのは、img に width と height の属性を書くことです。web.dev は「画像と video には常に width と height の属性を付ける」とし、最近のブラウザは属性から縦横比を計算して、読み込み前に領域を確保する、と説明しています。CSS で幅を伸縮させるときは height: auto を添えます。
<!-- 1) 属性で大きさを伝える(いちばん手軽) -->
<img src="photo.png" alt="写真" width="800" height="450">
<style> img { max-width: 100%; height: auto; } </style>
<!-- 2) CSS の aspect-ratio で領域を確保し、届くまで灰色にする -->
<img src="photo.png" alt="写真" class="ar">
<style> .ar { width: 100%; aspect-ratio: 16 / 9; background: #e5e5e5; } </style>
スケルトン(しましまのアニメーション)や LQIP(Low Quality Image Placeholder。小さくぼかした画像を先に出す)は、領域の確保に加えて「読み込み中」を伝える演出です。CLS を 0 にする効果は、属性を書くだけの方法と同じでした。web.dev は、広告や埋め込みが返ってこなかったときも確保した領域を畳まないこと(畳むと同じだけずれる)を勧めています。
画像の縦横比の指定は、関連記事「CSS object-fit・aspect-ratio|画像トリミング5パターン」で扱っています。
PowerPoint・Word・OneDriveのプレースホルダー
この節では、Web やプログラミング以外で出てくる「プレースホルダー」の意味が分かります。
PowerPoint のプレースホルダーは、スライドのレイアウトにあらかじめ置かれた、書式つきの入力枠です。 Microsoft のサポートページは「コンテンツ(テキスト、グラフィックス、またはビデオ)のスライド上の事前に書式設定されたコンテナー」と説明しています。「クリックしてタイトルを入力」の文字がプレースホルダーのプロンプトで、何も入力しなければ表示も印刷もされません。
| 場面 | プレースホルダーの意味 | 確かめた資料 |
|---|---|---|
| PowerPoint | レイアウトに置かれた入力枠。スライドマスター表示で追加・編集・削除する。テキストボックスは手で足す独立した枠で、レイアウト変更に追従しない | Microsoft サポート |
| Word | テンプレートや差し込み印刷の「ここに名前が入る」枠(コンテンツコントロール・フィールド) | 一般的な説明 |
| OneDrive などクラウドの同期(Windows) | 中身をまだ取得していないファイルの仮の実体。Microsoft Learn は「他の場所に存在する実際のコンテンツを表すファイル」と定義し、読み取りが来たときに中身を供給する、と説明している | Microsoft Learn(Cloud Files) |
| 翻訳・多言語対応 | 翻訳文の中の {count}・%1$s。翻訳者が訳さずに残す印 |
各ライブラリの決まり |
| LLM のプロンプト | プロンプトの雛形の {question}。実行時に質問文を差し込む |
文字列テンプレートと同じ |
どれも「本物があとから入る、仮のもの」という意味は共通です。翻訳文のプレースホルダーは文字列テンプレートの一種で、「{name}さん、{count}件」のように名前付きにしておくと、語順が違う言語でも訳せます。
よくあるエラー・つまずき(原文つき)
この節では、プレースホルダーにまつわるエラーの原文と、原因・直し方が分かります。
| 出た文言・現象 | 原因 | 直し方 |
|---|---|---|
| プレースホルダーが表示されない(type="date") | 日付・時刻・チェックボックスなどは placeholder に対応しない(手元で :placeholder-shown が false) |
欄の外に入力例を書く |
| 入力すると項目名が消えて何の欄か分からない | placeholder を label の代わりに使っている | label を付ける。欄の中に残したければフローティングラベル |
| プレースホルダーの文字が途中で切れる | 欄の幅より長い(220px に 27文字で 13文字しか見えなかった) | 短くする。説明は欄の外へ |
| axe などの検査で「コントラスト比が足りない」 | ::placeholder に #999 などの薄い色を指定した(2.85:1) |
#767676 以上の濃さにする(4.54:1) |
| 送信しても値が空 | placeholder を初期値と思っている | value 属性を使う |
Incorrect number of bindings supplied. The current statement uses 1, and there are 7 supplied. |
sqlite3 に文字列 "O'Brien" をそのまま渡し、7文字が7個の値と数えられた | (name,) のようにタプルにする |
Incorrect number of bindings supplied. The current statement uses 2, and there are 1 supplied. |
? の数と値の数が合わない |
値を数え直す |
near "?": syntax error |
表名・列名にプレースホルダーを使った | 許可リストと照合して文字列で組み立てる |
near "Brien": syntax error |
値を文字列連結で SQL に埋め込み、引用符で壊れた | プレースホルダーで渡す |
KeyError: 'age'(Python) |
テンプレートの {age} に値を渡していない |
名前の綴りと渡す値をそろえる |
%!d(MISSING) が出力に残る(Go) |
Printf の値が足りない。エラーにならない | go vet で検出できる。出力にこの文字列が無いか探す |
| フローティングラベルが最初から上にある | placeholder=" " を書いていない |
空白1文字の placeholder を付ける |
どの意味の「プレースホルダー」か決める
入力欄の文字か、文字列の穴か、SQL の値か、画像の領域か。質問や検索の前に場面をはっきりさせると、答えが早く見つかる。
入力欄なら label・色・長さを確かめる
label があるか、色が 4.5:1 以上か、欄に収まる長さか。DevTools の「要素」で ::placeholder の色を見る。
SQL なら値の渡し方を確かめる
第2引数で渡しているか、タプルか、表名に使っていないか。エラー原文の「bindings」「near」で切り分ける。
画像なら width/height を書く
DevTools の「パフォーマンス」や Lighthouse で CLS の原因の要素を見て、大きさの無い img に属性を足す。
よくある質問
Q. プレースホルダーとは何ですか?
A. あとから本当の値が入る場所に、仮に置いておく文字や領域のことです。HTML の入力欄に薄く出る「例:山田 太郎」、プログラムの文字列の {name}、SQL の ?、画像を読み込むまでの灰色の枠が代表例です。
Q. HTML でプレースホルダーを付けるには?
A. <input type="text" placeholder="例:山田 太郎"> のように placeholder 属性を書きます。text・search・url・tel・email・password・number の input と textarea で表示されます。date やチェックボックスには表示されません。
Q. プレースホルダーの色を変えるには?
A. CSS の ::placeholder 擬似要素で input::placeholder { color: #767676; } のように指定します。白い背景では #767676 以上の濃さにすると 4.5:1 を満たします。Firefox は半透明で描くため opacity: 1 も添えます。
Q. プレースホルダーの既定の色は何色ですか? A. 手元の Chromium 153 では rgb(117,117,117)(#757575)で、白背景とのコントラスト比は 4.61:1 でした。Chromium のソースコード(html.css)でも #757575 です。暗い背景では 3.62:1 まで下がるため、ダークモードでは色を指定し直します。
Q. プレースホルダーと label はどう違いますか? A. label は「この欄が何か」を示す名前で、入力中も見え、クリックすると欄にフォーカスが移り、支援技術に名前として伝わります。プレースホルダーは入力例で、入力すると消えます。項目名は label に、入力例はプレースホルダーに書きます。
Q. プレースホルダーに書いた文字は送信されますか?
A. 送信されません。手元で何も入力せずに送ると、本文は name=&mail= のように空でした。初期値として送りたい値は value 属性に書きます。
Q. 入力すると消えてしまうのを、残す方法はありますか?
A. プレースホルダーそのものは残せません。欄の上に小さく移る「フローティングラベル」を :placeholder-shown で作るか、欄の外に説明を置きます。
Q. プログラミングでいうプレースホルダーとは?
A. 文字列の中に置いた「あとで値を入れる印」です。Python の {name}、JavaScript の ${name}、C 系の %s・%d などで、実行時に値で置き換わります。値を渡し忘れると KeyError や MissingFormatArgumentException になります。
Q. SQL の ? や :name は何のためにありますか?
A. SQL 文と値を分けて渡すためです。値は SQL として解釈されないので、O'Brien のような引用符入りの値も正しく扱われ、文字列連結で起きる SQL インジェクションを防げます。手元の SQLite で 1 OR 1=1 を渡しても、その文字列と一致する行しか返りませんでした。
Q. SQL のプレースホルダーは表名にも使えますか?
A. 使えません。SELECT * FROM ? は near "?": syntax error になりました。表名・列名・並び順は、許可した名前の一覧と照合してから組み立てます。
Q. 画像のプレースホルダーとは何ですか? A. 画像が届くまでの間、同じ大きさの領域を確保しておくことです。img に width と height の属性を書くだけで、手元の計測では CLS が 0.0513 から 0 になりました。スケルトンやぼかし画像(LQIP)は、その上に「読み込み中」を伝える演出を足したものです。
Q. PowerPoint のプレースホルダーとテキストボックスの違いは? A. プレースホルダーはスライドのレイアウトに置かれた書式つきの枠で、スライドマスターで編集し、レイアウトを変えると内容が引き継がれます。テキストボックスは手で足す独立した枠です。Microsoft のサポートページで確かめた範囲です。
まとめ
- プレースホルダーとは「あとから本当の値が入る場所の、仮の文字や領域」。入力欄の薄い文字・文字列の穴・SQL のバインド変数・画像の仮の領域の4つで使われる。
- HTML の placeholder は値が空のときだけ表示され、送信されない。date などには表示されない。項目名は label に、入力例だけを placeholder に書く。
- Chromium 153 の既定色 #757575 は白背景で 4.61:1。暗い背景では 3.62:1、#999 は 2.85:1 で基準を下回る。
::placeholderで #767676 以上の濃さにする。 - SQL の
?・:nameは値を SQL と分けて渡す仕組み。引用符入りの値も正しく扱われ、文字列連結はnear "Brien": syntax errorで壊れた。表名には使えない。 - 画像は width/height か aspect-ratio で領域を確保すると CLS が 0.0513 から 0 になった。
参考・出典
確認日はいずれも 2026年10月29日です。
- MDN「HTML 属性: placeholder」:https://developer.mozilla.org/ja/docs/Web/HTML/Reference/Attributes/placeholder
- MDN「::placeholder」:https://developer.mozilla.org/ja/docs/Web/CSS/Reference/Selectors/::placeholder
- WHATWG「HTML Standard」4.10.5.3.10 The placeholder attribute:https://html.spec.whatwg.org/multipage/input.html#the-placeholder-attribute
- Chromium のソースコード「html.css」(::-webkit-input-placeholder の既定色):https://chromium.googlesource.com/chromium/src/+/main/third_party/blink/renderer/core/html/resources/html.css
- W3C「Understanding Success Criterion 1.4.3: Contrast (Minimum)」(WCAG 2.2):https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html
- Python「sqlite3 --- SQLite データベースに対する DB-API 2.0 インターフェース」:https://docs.python.org/ja/3/library/sqlite3.html
- Python「PEP 249 – Python Database API Specification v2.0」(paramstyle):https://peps.python.org/pep-0249/
- psycopg「Passing parameters to SQL queries」:https://www.psycopg.org/psycopg3/docs/basic/params.html
- PostgreSQL「PREPARE」:https://www.postgresql.org/docs/current/sql-prepare.html
- web.dev「Cumulative Layout Shift (CLS)」:https://web.dev/articles/cls
- web.dev「Optimize Cumulative Layout Shift」:https://web.dev/articles/optimize-cls
- Microsoft サポート「スライド レイアウトのプレースホルダーを追加、編集、または削除する」:https://support.microsoft.com/ja-JP/PowerPoint/add-edit-or-remove-a-placeholder-on-a-slide-layout
- Microsoft Learn「プレースホルダーについて」(Cloud Files):https://learn.microsoft.com/ja-jp/windows-hardware/drivers/ifs/placeholders
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「プレースホルダーとは|入力欄・テンプレート・SQL・画像の4つの意味と使い方」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。