2011-09-23更新: 一部を修正して Gist に置きました。
フォームの入力フィールドにあらかじめテキストを表示させておく「プレースホルダ」。ブラウザの検索バーなんかに見られるような、フィールドが空のときは薄く文字が表示されていて、フォーカスすると消えるあれです。このプレースホルダの機能、HTML5 では input
要素や textarea
要素の placeholder
属性で簡単に実現できます。
<label>お名前 <input type="text" name="fn" placeholder="山田 太郎"></label>
しかしながら、この placeholder
属性をサポートしているのは今のところ Safari と Chrome のみ。そのほかのブラウザでは無視されてしまいます。そこで、この placeholder
属性をクロスブラウザで扱えるようにする jQuery スクリプトを書いてみました。実際に動作しているデモ も用意したのでどうぞ。
$(function () {
var supportsInputAttribute = function (attr) {
var input = document.createElement('input');
return attr in input;
};
if (!supportsInputAttribute('placeholder')) {
$('[placeholder]').each(function () {
var
input = $(this),
placeholderText = input.attr('placeholder'),
placeholderColor = 'GrayText',
defaultColor = input.css('color');
input.
focus(function () {
if (input.val() === placeholderText) {
input.val('').css('color', defaultColor);
}
}).
blur(function () {
if (input.val() === '') {
input.val(placeholderText).css('color', placeholderColor);
} else if (input.val() === placeholderText) {
input.css('color', placeholderColor);
}
}).
blur().
parents('form').
submit(function () {
if (input.val() === placeholderText) {
input.val('');
}
});
});
}
});
解説してみます。まずはじめのポイントは、ブラウザが placeholder
属性をサポートしているかどうかを判定している点です。判定には実際にはドキュメントに現れないダミーの input
要素を作り、placeholder
プロパティの有無を調べます。その結果、もしブラウザが placeholder
をサポートしていればスクリプトは何もしません。以降のスクリプトはサポートしていないブラウザでのみ実行されます。
var supportsInputAttribute = function (attr) {
var input = document.createElement('input');
return attr in input; // 引数で指定された属性がサポートされていれば true を返す
};
if (!supportsInputAttribute('placeholder')) {
// placeholder 属性をサポートしないブラウザでのみ実行
}
placeholder
属性は input
要素だけではなく textarea
要素でも使われるので、セレクタは以下のように placeholder
属性を持つすべての要素を対象とします。
$('[placeholder]').each(function () {
// placeholder 属性を持つすべての要素で実行
});
次に、対象の各要素の placeholder
属性の値と、プレースホルダの前景色をそれぞれ変数に格納します。ここではプレースホルダの前景色に具体的な色ではなくシステムカラーの GrayText
を指定。OS やブラウザの GUI で選択できないテキストやなんかに使われる色ですね。実際の色は環境に依存するわけですが、だいたい #999
とか #aaa
あたりになるようです。また読み込み時のフィールドの前景色も保持しておきます。
var
input = $(this),
placeholderText = input.attr('placeholder'), // placeholder 属性の値
placeholderColor = 'GrayText', // プレースホルダの前景色
defaultColor = input.css('color'); // フィールドの本来の前景色
そして、フィールドがフォーカスを得たときと失ったときにその value
を調べ、プレースホルダの表示と非表示を実行します。ページの読み込み時にはフィールドがブラー状態になるようにし、その時点でフィールドが空なら placeholder
属性の値をフィールドにセット、そしてフォーカス時にプレースホルダが表示されていればそれを消去。同時に前景色も切り替えています。最後に、フィールドの value
にプレースホルダが入った状態でそのまま送信されないように、フォームのサブミット時にも値をチェックしています。
input.
focus(function () { // フォーカス時
if (input.val() === placeholderText) {
input.val('').css('color', defaultColor);
}
}).
blur(function () { // ブラー時 (フォーカスが外れたとき)
if (input.val() === '') {
input.val(placeholderText).css('color', placeholderColor);
} else if (input.val() === placeholderText) {
input.css('color', placeholderColor);
}
}).
blur(). // ページ読み込み時にいったんブラー
parents('form').
submit(function () { // サブミット時
if (input.val() === placeholderText) {
input.val('');
}
});
プレースホルダをどのように表現するかについては、新たに span
などの要素を生成して CSS でフィールドに重ねるという手法もありますが、ここではフィールドの value
にプレースホルダのテキストを突っ込むというアプローチを採りました。そのため、クライアントサイドでフォームをバリデートするようなスクリプトとの共存は難しいかもしれません。
またこのスクリプトの弱点として「placeholder
属性の値と同じ文字列をサブミットできない」という点があります。つまり、たとえば “Lorem ipsum” というプレースホルダが設定されたフィールドに “Lorem ipsum” という文字列を入力しても、それはプレースホルダと見なされてしまい送信できないわけです。これはうまく解決する方法が思いつかなかったので、とりあえずプレースホルダの文言を工夫するしかないです…
ところで、プレースホルダにはどのようなテキストがふさわしいのでしょうか。W3C の仕様では以下のように書かれています:
The placeholder
attribute represents a short hint (a word or short phrase) intended to aid the user with data entry. A hint could be a sample value or a brief description of the expected format. The attribute, if specified, must have a value that contains no U+000A LINE FEED (LF) or U+000D CARRIAGE RETURN (CR) characters.
Note: For a longer hint or other advisory text, the title
attribute is more appropriate.
The placeholder
attribute should not be used as an alternative to a label
.
(4.10.7.2.11 The placeholder attribute — HTML 5 [W3C Working Draft 4 March 2010])
というわけで、placeholder
が示すのは「ユーザのデータ入力を補助するためのちょっとしたヒント」といったところですね。具体的には「こんな感じで入力してくださいね」という記入例のようなものなどでしょうか。また長いヒントや注意書きなどは title
属性のほうがよいでしょう、とされています。ちなみに今回のスクリプトの デモ は上記仕様にあったマークアップ例を使わせてもらってます。
とくに注意したいのが「label
要素の代替として用いられるべきではない」という部分です。たとえば以下のようなマークアップはけっこうやってしまいそうですが、あまりよろしくないですね:
<input type="text" placeholder="お名前">
<input type="email" placeholder="メールアドレス">