入力欄のプレースホルダーって結局どうなの

入力欄のプレースホルダーの話をします。プレースホルダーというのは、フォームの入力欄で、ユーザーが入力するまでの間に表示されているテキストのことです。

![「入力欄:」というラベルの横に1行の入力欄があり、「これがプレースホルダー」というプレースホルダーが表示されている](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22333/1003f66c-cf37-b31d-59db-dba478f4cd44.png)

```html
<label>入力欄: <input type="text" placeholder="これがプレースホルダー"></label>
```

書籍「[Webアプリケーションアクセシビリティ](https://webapp-a11y.com/)[^1]」では、「3.1 ラベルと説明」のところで、紙版にして約1.5ページの分量を割いて、フォーム入力欄のプレースホルダー（`<input>` 要素や`<textarea>` 要素の `<placeholder>` 属性）の問題点を指摘しています。

[^1]: 私は書籍「[Webアプリケーションアクセシビリティ](https://webapp-a11y.com/)」の共著者のひとりですが、ここを書いたのは別の人です

この本で指摘されているプレースホルダーの問題点は以下の3つです。

> - プレースホルダーの色が薄く視認しづらい
> - プレースホルダーとフォームコントロールの値との区別がつかない
> - フォームコントロールに値を入力したときにプレースホルダーの値が見えなくなってしまう
>
> <cite>[Webアプリケーションアクセシビリティ](https://webapp-a11y.com/)</cite>

さらに、[Nielsen Norman Groupによる「Placeholders in Form Fields Are Harmful」](https://www.nngroup.com/articles/form-design-placeholders/)（[日本語訳: 入力フォームのプレースホルダーを使ってはいけない](https://u-site.jp/alertbox/form-design-placeholders)）で数々の問題点が指摘されていること、HTMLの仕様書の[placeholder属性の項目](https://html.spec.whatwg.org/multipage/input.html#the-placeholder-attribute)（[placeholderの項目の日本語訳](https://momdo.github.io/html/input.html#the-placeholder-attribute)）にて、「label要素の代替として使用するべきでない」「『短いヒント』を表す」とされていることを紹介しています。

このように、入力欄のプレースホルダーに関して数々の問題点が指摘されていながらも、なおプレースホルダーのある入力欄をあちこちで見かけます。新たにプレースホルダーを採用しようとする人、これらの問題点を指摘されてもなお使いたがる人に出会ったこともあります。

実は、国際標準となっているアクセシビリティガイドラインである[WCAG 2.2](https://www.w3.org/TR/WCAG22/)（[WCAG 2.2 日本語訳](https://waic.jp/translations/WCAG22/)）および関連文書では、明確にプレースホルダーの使用を制限するような項目は、自分が知る限り存在しません。それどころか、アクセシビリティの検証に使われるaxeやLighthouseは、ラベルの関連付けのない入力欄の問題は指摘しますが、placeholder属性を指定すると、この問題を指摘しなくなってしまいます。

ということで、入力欄のプレースホルダー、すなわちHTMLの `<input>` `<texteare>` の `placeholder` 属性についてまとめてみます。ちょうどQiitaさんが[アクセシビリティの知見を発信しよう！](https://qiita.com/official-events/4d9893df2bfd52211392)キャンペーンをやっているので、それに便乗する意図もあります。


## 前提: 入力欄とラベルとプレースホルダー

この話をするための前提として、HTMLのフォームの入力欄で使われているものの名前を整理しておかなければなりません。

ここでは、以下のように呼ぶことにします。

<dl>
<dt>入力欄</dt>
<dd>ユーザーが文字入力をするのに使われる部品。HTMLでは <code>&lt;input&gt;</code> 要素や <code>&lt;textarea&gt;</code> 要素で作られる。<br>（書籍からの引用では「フォームコントロール」と呼んでいますが、この記事では引用部を除いて「入力欄」と呼ぶことにます）</dd>
<dt>値（入力値）</dt>
<dd>ユーザーが入力した文字列</dd>
<dt>ラベル</dt>
<dd>入力欄を識別する文字列。HTMLでは <code>&lt;label&gt;</code> 要素を使い、 <code>&lt;label&gt;</code> 要素内に入力欄を配置するか、入力欄の要素の <code>id</code> 属性と同じ値を <code>&lt;label&gt;</code> 要素の <code>for</code> 属性に指定することで入力欄と紐付ける。</dd>
<dt>プレースホルダー</dt>
<dd>ユーザーが入力欄に入力を始めるまでの間、入力欄に表示されている文字列。HTMLでは<code>&lt;input&gt;</code> 要素や <code>&lt;textarea&gt;</code> 要素で作られる</dd>
</dl>

たとえば以下の例では、「名前」がラベル、「鈴木 太郎」がプレースホルダーとして使われています。入力前なので値はありません。

![「名前」ラベルの横に「鈴木 太郎」がプレースホルダーとして表示された入力欄がある。「ラベル」は茶色、「入力欄」は紺色、「プレースホルダー」は緑色の四角形で囲まれ、それぞれ近くに「ラベル」「入力欄」「プレースホルダー」と同じ色の文字で書かれている](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22333/1dd543fd-3916-289f-29ff-ead6f27c9a35.png)

```html
<label for="name">名前</label>
<input type="text" id="name" placeholder="鈴木 太郎">
```


## プレースホルダーの使われ方

冒頭で紹介したとおり、HTMLの仕様書には「プレースホルダー（ `placeholder` 属性）をラベル（`<label>`要素）の代替として使うべきではない」ということが書かれています。しかし、プレースホルダーはさまざまな使われ方をしています。どれか1つの使い方についてだけ「するべきでない」と書かれているだけだと、それ以外の使い方をしようとしている人は困ってしまうのではないかと思います。

というわけで、思いつく限りの使われ方を整理しておきます。

### A: ラベルの代替として使われている

HTMLで名指しでやるべきではないとされている使われ方です。入力前の状態でスッキリして見えることから、こういう使われ方をされてしまうことがあるようです。

![プレースホルダーに「名前」と書かれた入力欄。ラベルは存在しない](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22333/5aa8d058-95c4-1fe0-6b19-30c4416e1494.png)

```html
<input type="text" placeholder="名前">
```

### B: 記入例を示すために使われている

これもよく見る気がします。以下の例では記入例がそのまま入っていますが、「例) 鈴木 太郎」のように、記入例であることがわかるような書き方をしている場合もあります。

![「名前」ラベルと、「鈴木 太郎」がプレースホルダーとして表示された入力欄](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22333/d6536c05-7496-4878-5d75-0359c98e1762.png)
```html
<label for="name">名前</label>
<input type="text" id="name" placeholder="鈴木 太郎">
```

### C: 入力規則を示すために使われている

「半角英数」や「全角」や「何文字以上何文字以内」みたいな情報が書かれているパターンです。こちらもよく見かけます。

![「パスワード」ラベルと、「半角英数20文字以内」がプレースホルダとして表示された入力欄](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22333/d66a615b-a411-52af-d513-4f025965a247.png)

```html
<label for="password">パスワード</label>
<input type="password" id="pasword" placeholder="半角英数20文字以内">
```

### D: その他のメッセージや、AからCの組み合わせを示すために使われている

「入力してください」のように入力を促す文言であったり、これまでに紹介したものの組み合わせ（「全角で入力してください（例: 鈴木 太郎）」のようなもの）だったりを見かけます。


## プレースホルダーの使用の問題点を改めて考えてみる

さて、ここで、冒頭で紹介した3つの問題点をもう一度考えてみます

### プレースホルダーの色が薄く視認しづらい

プレースホルダーの色は、プレースホルダー自体の視認性の問題なので、プレースホルダーを何に使っていても、関係があります。しかしこれは「問題のあるケースと、そうでないケースがある」としか言いようがないのではないでしょうか。

プレースホルダーは、だいたいの場合、入力値よりも「薄い」（コントラスト比の低い）色で表示されます。調べてみたところ、Chromeのユーザーエージェントスタイルシートでは `color: #757575` となっていました。Firefoxでは `opacity: 0.54` がついていて、背景色 `#FFFFFF` 文字色 `#000000` であればChromeと同じく `#757575` あたりになる状態になっていました。

これらの色は、WCAGのレベルAAの達成基準である[1.4.3 Contrast (Minimum)](https://www.w3.org/TR/WCAG22/#contrast-minimum)（[1.4.3 コントラスト (最低限)](https://waic.jp/translations/WCAG22/#contrast-minimum)）でテキストに求められている、4.5:1のコントラスト比を満たす色の組み合わせとなっています。ただし、背景色や文字色を変えた場合には必ずしもそうはなりません。 

`placeholder` は `::placeholder` 疑似要素としてスタイルの変更が可能です。**Firefoxでは `opacity` が指定されているため、想定よりも低いコントラスト比になりやすい点には注意が必要です**。想定通りの色となるよう、 `opacity` を同時に指定しておくのがよさそうです。

```css
input::placeholder, textarea::placeholder {
  color: #666666;
  opacity: 1; /* Firefoxでは ::placeholder に opacity が指定されているため、1を指定しないと想定よりも「薄い」色になってしまう */
}
```

なお、WCAGにはレベルAAAの達成基準として[1.4.6 Contrast (Enhanced)](https://www.w3.org/TR/WCAG22/#contrast-enhanced)（[1.4.6 コントラスト (高度)](https://waic.jp/translations/WCAG22/#contrast-enhanced)）が存在します。ここで求められているコントラスト比は 7:1 であり、より「濃い」色が求められていることには注意が必要です。

### プレースホルダーと入力値との区別がつかない

これは特に「B: 記入例を示すために使われている」の場合に困ったことになります。プレースホルダーとしてもっともらしい文字列が記載されていると、記入済みのように見えてしまうかもしれません。

たとえば以下の画像は、上が記入済み、下は記入前です。

![「国籍」ラベルと入力欄の組み合わせが、上下に2つ並んでいる。上の記入欄には少し薄い色で「日本」、下は濃い色で「日本」と書かれている](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22333/c9428b06-a54c-27e0-ccf1-c4004145ec2b.png)

```html
<label for="nationality">国籍</label>
<input type="text" id="nationality" placeholder="日本">
```

明らかに記入例だとわかるような文字列なら、プレースホルダーであることに気付けるかもしれませんが、上記の例は「国籍」欄に「日本」という、多くの人にあてはまる内容が書かれています。国籍が日本以外の人であれば書き換えるでしょうが、日本国籍の人は「記入済みなんだな」と思って素通りしてしまうかもしれません。特に、ユーザー登録してログインした状態で使う画面でこんなもっともらしい記入例のプレースホルダーがあると、「ユーザー登録したときの情報で埋めておいてくれたのかな、親切だな」と思ってしまう確率は高まります。

そして未記入のまま進もうとすると「入力必須の項目が記入されていません」と止められ、フォームを見返してみてもどこが未記入なのかわからない、ということになったりします。あるいは未記入のまま進んでしまい、ユーザーの意図とは違うデータとして保存されてしまうかもしれません。

これを防ぐには、 **そもそも記入例をプレースホルダーにせず、入力欄の外に書く** べきですが、どうしてもプレースホルダーを使いたいのであれば、以下のような対策が考えられます。

- 「（例）○○」のように、記入例であることがわかる文字列にする
- プレースホルダーの見た目を、入力値と明らかに違う見た目にする

たとえば先ほどのフォームの記入例も、「（例）日本」とするだけで、色の違いまで注意深く見なくても、記入例であることがわかりやすくなります。

さらにプレースホルダーの見た目を変えてしまうことでより差が際立つはずです。ただしフォントサイズや色による差別化は、敏感に気付ける人とそうでない人の差が大きいため、頼りすぎるべきではありません。また、一定以上のコントラスト比を保ちながら、入力値と区別しやすい色を選ぶ難しさもあります。

以下は、フォントサイズを小さくして、プレースホルダーに「（例）」を足して記入例であることを明確にした例です。

![プレースホルダーの内容を「（例）日本」とし、文字サイズを小さくした例と、記入済みのテキストフィールド](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22333/b33fe08c-4bee-15d9-f50f-1705212e5a53.png)

#### スクリーンリーダーではどうなるのか

ところで、プレースホルダーについて話をしているとき、スクリーンリーダーを使っている同僚が「プレースホルダーはスクリーンリーダーにとって、入力値と区別がつきづらい」という話をしていました。ということで、[日本で大きなシェアを誇るスクリーンリーダー](https://jbict.net/survey/at-survey-03)である[PC-Talker](https://www.aok-net.com/screenreader/)の[クリエイター版](https://www.aok-net.com/pctksdk.htm)[^2]と、[NVDA日本語版](https://www.nvda.jp/)で試してみました。

[^2]:[PC-Talker](https://www.aok-net.com/screenreader/)の[クリエイター版](https://www.aok-net.com/pctksdk.htm)は音声を出力できないため、声の高さなどによって差異が表現されている場合などには気付くことができません

PC-Talkerと専用ブラウザのNetReader Neoでは、上の「国籍」の例では、プレースホルダーに「日本」が入っているものも、入力値に「日本」が入っているものも、 どちらも「国籍　文字入力　日本」と読んでしまい、全く区別が付かない状態になってしまいました 。また、PC-TalkerでChromeを操作した場合、そもそもプレースホルダーを読み上げませんでした。

NVDAとChromeの組み合わせの場合、「ブラウズモード」では、プレースホルダーとして「日本」が入っている場合も、入力値として「日本」が入っている場合も、どちらも「国籍 エディット 日本」と読んでしまい、全く区別がつかない状態になってしまいました。NVDAには「ブラウズモード」と「フォーカスモード」の2つのモードがあり、フォームに入力するときなどは「フォーカスモード」を使用します。「フォーカスモード」であれば「ブランク」と言ったり、入力済みフィールドへのフォーカス時に文字列を選択した状態になって「選択」と言ったりしてくれますが、入力内容を確認するためにユーザーが必ずフォーカスモードを使ってくれるとは限りません。

すなわちプレースホルダーによる記入例は、やはり「（例）」など記入例であることがわかるような文字列になっている必要があることは間違いないでしょう。その場合も、ユーザーが自身で「（例）」などを入力した場合に区別が付かなくなる問題があり、「Webフォームを作成するWebフォーム」のようにそういった内容を入力することが想定される場合には特に、プレースホルダーに記入例を書くべきではないでしょう。

### 入力欄に値を入力したときにプレースホルダーが見えなくなってしまう

これはどんな使い方をしていても問題になってしまいますが、特に問題が大きいのは「A: ラベルの代替として使われている」「C: 入力規則を示すために使われている」場合でしょう。

「A: ラベルの代替として使われている」場合、文字を入力すると何の欄だったかわからなくなってしまいます。入力時には入力直前まで見えていたので困らないかもしれませんが、いろいろな欄への記入をし終えて、送信前に確認しようとすると、ユーザー自身の入力内容からその欄が何の欄だったのかを推測しなければならなくなります。

また、「C: 入力規則を示すために使われている」の場合、入力中に困ってしまうことも起きます。「何文字以上何文字以下」「数字は全角」「苗字と名前の間は半角スペースを入れる」のような細かな指定は、入力中に確認しないと不安になるし、入力しはじめてすぐ忘れてしまうことだって考えられます。

![「パスワード」のラベルと入力欄が上下に2つ並べられている。上の入力欄は入力前で、「半角英数20文字以内」とプレースホルダーに書かれているのが見える。下の入力欄は何かが入力されていて、入力規則はわからない](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22333/a2689097-da79-3b0f-8a31-42deb480f1d9.png)

このように入力中や入力後に、ラベルや入力規則のような情報が見えなくなってしまうのは、入力内容の正しさをユーザーが確認できず不安になってしまったり、あるいは正しい内容が送られてこないことに繋がっていってしまいます。 **正しい記入や内容の確認に必要な情報はプレースホルダーに書かず、入力欄の外に書くべき** です。

## プレースホルダーの内容を外に出す

プレースホルダーに書かれた内容は、入力中や入力後に読むことができません。ここまで指摘したとおり記入や確認に必要な情報をプレースホルダーに書くべきではないです。

記入例は記入や確認に、すべての場合において必須とまでは言えないため、この記事の公開時点では、記入例にプレースホルダーの利用を避けるべきであると断言はしていませんでした。その結果、「記入例は『（例）』をつけたり、スタイルを変えたりすればプレースホルダーで良い」と理解してしまっている反応が見られました。

この記事で紹介した、「（例）」を付けたりスタイルに差をつけたりする例は、 **あくまで「どうしてもプレースホルダーを使いたいのであれば」の例** であって、 **記入例であってもプレースホルダーではなく、入力欄の外にあるほうが望ましい** です。

たとえばこういう感じです。

![「国籍（例：日本）」というラベルの横に入力欄がある](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22333/507bf228-a0c7-647c-a200-ddf26f1ddcef.png)

```html
<label for="nationality">国籍（例:日本）</label>
<input type="text" id="nationality">
```

この例では、記入例をプレースホルダーではなく、ラベルに含めています。記入例の存在が目立ちすぎるのが気になるのなら、控えめな見た目にするのも良いでしょう。

![「（例：日本）」の部分の色をグレーにして、文字サイズを下げた例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22333/7739f291-1be8-ee30-c93c-a7f235206f6d.png)

```html
<label for="nationality">国籍<span class="description">（例:日本）</span></label>
<input type="text" id="nationality">
```

```css
.description {
  font-size: 0.75em;
  color: #757575;
}
```

記入例や入力規則をラベルに含めると、入力欄と関連付けれていることが明確になり、スクリーンリーダー等の支援技術に項目名と一緒に伝わる利点があります。記入例や入力規則をラベルに含めない場合は、 `aria-describedby` でスクリーンリーダー等の支援技術向けに情報を紐付けるのもよいでしょう。

以下の例では、 `aria-describedby` でスクリーンリーダー等の支援技術向けに情報を紐付けています。HTMLの記述順は記入例のあとに入力欄を置いていますが、CSSで `flex-direction: column-reverse` を使って入力欄の後ろに記入例があるように見せています。この順にするのは、スクリーンリーダーで順番に読んでいるときには入力欄よりも先に記入例を読むことができ、記入例を `aria-describedby` のみで示すよりも気付いてもらいやすくする意図があります。

![「国籍」のラベル、入力欄、「（例：日本）のグレーのテキスト」の順で縦に並んでいる](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22333/111b0fa2-c3a7-8a5e-689c-b5fe8867d748.png)

```html
<label for="nationality">国籍</label>
<div class="field-description">
  <span class="description" id="nationality-description">（例:日本）</span>
  <input
    type="text"
    id="nationality"
    aria-describedby="nationality-description"
  />
</div>
```

```css
.field-description {
  display: flex;
  align-items: start;
  flex-direction: column-reverse;
}
```

## プレースホルダーを使っても良いケースはあるのか

ここまで書いたとおり、プレースホルダーは肝心なときに見えなくなってしまったり、記入済みの情報と区別がつかなくなってしまい、その可能性が少しでもある場合には利用を避けるべきです。

なお、HTMLの仕様書には、placeholderの用途として以下のようなことが書かれています。

>The placeholder attribute represents a short hint (a word or short phrase) intended to aid the user with data entry when the control has no value. A hint could be a sample value or a brief description of the expected format. （中略）
>
>The placeholder attribute should not be used as an alternative to a label. For a longer hint or other advisory text, the title attribute is more appropriate.
>
> <cite><a href="https://html.spec.whatwg.org/#the-placeholder-attribute">4.10.5.3.10 The placeholder attribute (HTML Standard)</a></cite>

> コントロールが値を持たない場合、placeholder属性は、データ入力を伴うユーザーの支援を意図する短いヒント（単語や短いフレーズ）を表す。ヒントは、サンプル値または期待された形式の簡単な説明かもしれない。（中略）
>
> placeholder属性は、labelの代替として使用すべきでない。より長いヒントまたは他の助言テキストの場合、title属性がより適切である。
>
> <cite><a href="https://momdo.github.io/html/input.html#the-placeholder-attribute">4.10.5.3.10 placeholder属性（HTML Standard 日本語訳）</a></cite>

そしてこの下には、メールアカウントの入力フォームの例が示され、「Name」「Address」「Description」の入力には `placeholder` 属性に（特に例示であることを示す文字列をつけずに）記入例が示されています。

これは……、ユーザーが自分のことを記入する欄なので、違う人の名前であれば記入済みの内容と誤認することはないだろう、ということなのかもしれません。あるいはHTMLの仕様書では単に `placeholder` というものの定義をしているだけで、ユーザーがそれを読んで記入済みテキストと誤認するかしないかはスコープ外、ということかもしれません。

プレースホルダーの面白い活用例としては、Slackの検索フィールドが、フォーカスするたびにプレースホルダーでちょっとずつ違うことを言ってくるというのもあります。こういう茶目っ気を出すのに使うのならたぶん問題ないでしょう。

![検索してみましょう。スクロールするより早く見つかりますよ！](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22333/4f119edb-57f8-bc37-61d8-95e6f9338154.png)
![探し物がある？こちらでどうぞ！](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22333/41a7e2e4-fe73-9359-3aaf-7689dc689d81.png)
![欠けている情報をアレコレ検索](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22333/e3977ded-86e2-c348-5981-fc9dd9914849.png)

なお、`<label>` 要素によるラベルの紐付けがない場合に、`title` 属性と `placeholder` 属性がラベルの代替として、スクリーンリーダー等への情報提示に使われる仕様が存在します（自力で仕様書を読んでも見つけられなくてブラウザが勝手にやっているのかと思っていたら、[HTML Accessibility API Mappingsに定義がある](https://www.w3.org/TR/html-aam-1.0/#input-type-text-input-type-password-input-type-number-input-type-search-input-type-tel-input-type-email-input-type-url-and-textarea-element-accessible-name-computation)のを[@momdo_](https://twitter.com/momdo_)さんに教えていただきました。ありがとうございます！）。これを理由に冒頭で紹介したaxeやLighthouseでは問題として指摘をしなくなったようですが、HTML仕様書に書かれているとおり、またこの記事でさんざん問題点を指摘したとおり、 `<label>` 要素の代替として `placeholder` 属性を使用するべきではありません。