Float Label Patternはかっこよくて、単にラベルをプレースホルダーにするよりはマシなので使いたくなる。しかしラベルとプレースホルダーは別に提供してやりたい。機能も違うものなので、その方がきっと良いはずだ。そこで別解として、ラベルが斜めに動くものを考えた。もちろんCSSのみで実装している。
Demo: Alternative Float Label Pattern
入力フォームにフォーカスすると、左にあるラベルが斜め右上に少し移動すると同時に入力フォームが左へ拡大する。これによりFloat Label Patternと同じような結果になるが、デフォルトの状態ではラベルとプレースホルダーを両立させることができる。
ラベルを入力フォームのフォーカスと連携させるには、隣接兄弟セレクターを使うくらいしか方法はなさそうなので、マークアップは入力フォーム→ラベルの順にする必要がある。またそうするためには、両者の関連付けもネストではなくfor
属性を使う必要もある。
<form>
<p>
<input id="foo"
type="text"
placeholder="Input example for Foo">
<label for="foo">Foo:</label>
</p>
</form>
CSSでは親要素(ここではp
要素)の高さと幅を制限した上で、margin-left
やtop
プロパティーなどをうまく使ってレイアウトしてやる。
仮に18em
(iPhoneのportraitでも収まる幅)、ラベルで6em
と入力フォームで12em
を使うとすると以下の様なCSSになる。
p {
width: 18em;
height: 2em;
}
input,
label {
-moz-box-sizing: border-box;
box-sizing: border-box;
display: inline-block;
}
input {
margin-left: 6em;
width: 12em;
height: 2em;
line-height: 2;
}
label {
position: relative;
top: -1.5em;
left: 0;
height: 1em;
line-height: 1;
}
入力フォームの位置はmargin-left
プロパティーでラベルの幅分の余白を作ってやり、width
プロパティーで12em
を指定しておく。ラベルではposition: relative
を使い、位置を上にずらす。両者ともにheight
とline-height
プロパティーを使って適切な高さを指定しておくが、ラベルをちょっと重ねることを考えると、入力フォームは最低でも2em
程度は必要になる。
あとはこれをinput:focus
をトリガーにして、入力フォームとラベルの位置を動かしてやるだけだ。入力フォームはmargin-left
とwidth
プロパティーで、ラベルはtop
とleft
プロパティーで動かす。
input:focus {
margin-left: 0;
width: 18em;
}
input:focus + label {
top: -2.5em;
left: 0.5em;
}
アニメーションはtransition
プロパティーを使って適当にやれば良い。元ネタのFloat Label Patternのように下線のみのフォーム要素の場合にはもうちょっと単純化できると思う。その一方で描画領域や親要素の大きさに合わせてフレキシブルに入力フォームの幅を調整するのは難しい(うまい方法が思いつかなかった)。
元々のFloat Label Patternの要件は以下の通りだと考えている。
このパターンの問題点は、ラベルとプレースホルダーを混同させずに両立させるのが難しいことだ。入力フォームに重なって表示された文字列をラベルと解釈させるには、アイコンの追加なども含め、かなり気を使って作りこむ必要がある。もしくはそのような形でのプレースホルダーの濫用による、ユーザーの慣れを期待することになる。
僕が考えたパターンは、元パターンの要件を満たした上でラベルとプレースホルダーの両立を実現している。
しかし同時に、入力フォームの入力開始位置が動くという別の新たな欠点も持ってしまう。元パターンでもラベルの移動により視線を奪うことは起こりうるので、元パターンとの比較では欠点とまではならないが、ユーザビリティ的な問題を解消しようとして別のユーザービリティ上の問題を抱えることになるので、あまり良い解とは言えないかもしれない。