この記事は、http://css-tricks.com/ の Chris Coyier の許可を得て、一部変更し、翻訳しています。オリジナルの記事はここよりご覧いただけます。
レンジ入力欄をHTML5で作成するとこのようになります:
<input type="range" name="quantity" min="1" max="10">
対応しているブラウザでは以下のように表示されます:
これは非常に便利な機能で、ユーザーから最小値や最大値を収集したい場合には、どこでも使用することが出来ます。
しかし、少し変だと思いませんか?
このスライダーだけだと、レンジ入力欄はユーザーに対し実際に送信される正確な「数値」を目視させていないのです。もしあなたの質問事項が「お元気ですか?」だったとして、左に行けば行くほど「哀しい」、右に行けば行くほど「嬉しい」というような値を表現しているのであれば、実際にユーザーに数値を確認してもらう必要はないかもしれません。けれども大抵は数値を表示させる方が無難なことが多いでしょう。
公正を期すために、スペックにはどのように書かれているか参照すると:
input要素とは、数値を表す文字列に要素の値を設定する働きをしますが、正確な値は重要ではないという警告が付いており、UAにより数値を求める時よりも、シンプルなインターフェースを提供させることを可能にしています。
けれども、それは自分たちが見栄えの良いスライダーを使用したいがために、送信した数値をユーザーに見せなくていいということにはつながりません。
各ブラウザがUIコントロールを変更して、自動的に数値を表示するようにしてくれたらありがたいのですが、まぁ自分たちで作ることにしましょう!
このような場合にはoutputタグの使用がベストです。outputタグとはform要素内での何らかの計算結果を表示する時に使用されます。とてもシンプルな実装サンプルをご覧下さい。
<input type="range" name="foo"> <output for="foo" onforminput="value = foo.valueAsNumber;"></output>
けれど、こんなインラインJavaScriptは今どき流行らないし、jQueryを参照してCSSできちんと処理した方がよいでしょう。今回のゴールは、時間を求めたり、最低値最大値、またステップなどを求めたりと、どのようなレンジ入力欄の使い方をしたとしても、スライダー上の吹き出しに現在値を表示させることです。
それではまずoutput要素のスタイルを指定しましょう。当然のことながら、input要素の前に記入します。そうすることにより、一度JavaScriptで設定してしまえば、残りの値も調整することが可能になります。疑似要素でグラデーションを付けてたり、角を丸く削ったり、小さな三角形のポインタを付けることも出来ます。
output { position: absolute; background-image: -moz-linear-gradient(top, #444444, #999999); background-image: -o-linear-gradient(top, #444444, #999999); background-image: -webkit-gradient(linear, left top, left bottom, from(#444444), to(#999999)); background-image: -webkit-linear-gradient(top, #444444, #999999); width: 40px; height: 30px; text-align: center; color: white; border-radius: 10px; display: inline-block; font: bold 15px/30px Georgia; bottom: 175%; left: 0; margin-left: -1%; } output:after { content: ""; position: absolute; width: 0; height: 0; border-top: 10px solid #999999; border-left: 5px solid transparent; border-right: 5px solid transparent; top: 100%; left: 50%; margin-left: -5px; margin-top: -1px; }
次にすべきことは、全ての範囲において数値の変化を確認することです。すなわち今回の目的は、スライダーのスペースで吹き出しの左側をシフトしてみることです。
スライダーの入力幅や最小値最大値は任意に設定可能なので、これは言うほど簡単なことではありません。
少し数学のお勉強もしてみましょう。こちらはjQueryのJavaScriptで、コメントも載せてあります:
$(function() { var el, newPoint, newPlace, offset; // 全部のinput要素の変化を監視 $("input[type='range']").change(function() { // とりあえず、変化のあった要素をキャッシュしておきます el = $(this); // 変化のあった要素の横幅を記録 width = el.width(); // 現在の位置がパーセントで言うとどの場所か計算します newPoint = (el.val() - el.attr("min")) / (el.attr("max") - el.attr("min")); // 場所の調整する為の数値の設定 offset = -1.3; // 左や右に行き過ぎないように、エラーハンドルとしていれます if (newPoint < 0) { newPlace = 0; } else if (newPoint > 1) { newPlace = width; } else { newPlace = width * newPoint + offset; offset -= newPoint; } // outputのタグを実際に動かします。 el .next("output") .css({ left: newPlace, marginLeft: offset + "%" }) .text(el.val()); }) // ページが一番最初にロードした際に、inputタグに変化があったと発動させることで、このファンクションを稼働させます .trigger('change'); });
大変だったのは、1.3の値のところです。吹き出しの尖がった先端を、スライダーの真ん中に揃えようとしましたが、それは簡単ではありません。何故ならスライダーの真ん中が100%左端または右端に行くことはないからです。従ってこの数値は完璧ではありませんが、何もないよりは幾分かマシでしょう。
ボーナスとしては、レンジ入力をサポートしていない各ブラウザでも、吹き出しの動作を表示してくれます。
備考:上記のコードは最小値と最大値が定められているレンジ入力欄に対して有効であって、もし最小値と最大値が無い場合は、うまく動作しません。私は最小値と最大値を設定しないでレンジ入力欄を使用するのは少し違和感を覚えますが、もし最小値と最大値を設定しなかった場合、デフォルト値は0から100です。それを証明するには下記のコードでテストしてみてください。もし下記のコードに変なところがあれば、修正して試してみてください。こんな感じになると思いますよ。
var minValue, maxValue; if (!el.attr("min")) { minValue = 0; } else { minValue = el.attr("min"); }
それでは最小値と最大値を算出してみてくださいね。こちらにライブデモもありますので、よろしければご覧ください。改善案はいつでも大歓迎です!