WWW Watch

HTML5 input type="range" で作る 「へぇボタン」

HTML5 で input 要素の type 属性として追加された 「range」 を使って、「へぇボタン」 を作ってみました。

へぇボタンHTML5 で input 要素の type 属性として追加された 「range」 は、数値を表す文字列をセットするための、スライダー形式やそれに準じた入力コントロールを作りますが、この input type="range" でちょっとしたお遊び。

昔の人気番組、「トリビアの泉」 でおなじみの、「へぇボタン」 を、input type="range" と CSS、簡単な JavaScript で作ってみました。完全な再現ではなくて、ボタンを押すと input type="range" で表示したスライダーの数値が上がるっていう、ちょっとだけ実用的 (?) なサンプルです。

実際のサンプルは下記に。

現在、最新版の Google ChromeSafari、および IE10 では動くと思います。あと手持ちの iOS 6 Safari と、Nexus 7 搭載 Chrome では動作確認しました。他のスマートフォンとかは知らない。

Firefox に関しては、昨日公開された最新の Firefox 21 は、まだ input type="range" に対応していません。現在 Beta Channel、2013年 6月 25日に正式リリース予定の、Firefox 22 以降であれば動作します。

HTML5 の audio 要素による、音声再生の部分では、Firefox の性能がいいので、Firefox 以外のブラウザだと、ボタンを連打したときに、音声がうまく再生されないんですよね。再生が遅れたりもするし。なので、本当は Firefox 22 以降で確認してもらう方がいいんですが。

HTML5 input type="range" で作る へぇボタン

HTML5 input type="range" とは

4.10.7.1.14 Range state (type=range)

When an input element's type attribute is in the Range state, the rules in this section apply.

The input element represents a control for setting the element's value to a string representing a number, but with the caveat that the exact value is not important, letting UAs provide a simpler interface than they do for the Number state.

Note: In this state, the range and step constraints are enforced even during user input, and there is no way to set the value to the empty string.

4.10.7.1.14 Range state (type=range) : HTML5 W3C Candidate Recommendation 17 December 2012 から引用

数値を表す文字列をセットするための入力コントロールを表します。ただし、正確な値が重要ではない入力コントロールになります。数値を入力する、input type="range" より簡単なユーザーインターフェースを提供可能です。

input type="range" は、最新版の Google Chrome (25 以降)、Safari (5.1 以降)、IE (IE10) で対応していますが、 Firefox も昨日、Beta Channel に移行した (つまり次の正式リリースバージョン) の Firefox 22 から、この input type="range" に対応しました。

サンプルの解説

ということで解説です。まずは、へぇボタンのソースコードから。

<!-- ↓へぇボタンの HTML↓ -->
<form>
 <div id="renge">
  <p><input type="range" name="hee" id="hee" min="0" max="20" value="0" /></p>
 </div>
 <label for="hee"><img src="img/hee.png" width="100" height="100" alt="へぇ" /></label>
</form>

とっても単純。 input type="range" が、得点ゲージ、その下にある、label 要素内に単純に 「へぇボタン」 の画像を置いているだけです。

input type="range" とあわせて、min="0" max="20" value="0" を指定することで、初期値 0、かつ、スライダーの選択範囲を 0~20 の間の数値に限定します。

で、次に基本的なスタイルの指定ですが、

.sample #hee {
  height: 300px;
  margin: 0;
  padding: 0;
  -webkit-transform: rotate(-90deg);
  transform: rotate(-90deg);
  width: 300px;
}

input 要素を、縦にするため、transform: rotate(-90deg); で 90度回転させます。また、あとで背景を設定したりするために、縦横サイズも指定してあります。

なお、再現性を考えればスライダー自体を消しちゃってもいいんですが、今回は再現性より、input type="range" がボタンに連動して動くのが大事なので、表示はそのままに。

音声再生は HTML5 audio 要素で

音声再生は HTML5 の audio 要素でやります。「へぇ~」 の音声ファイルを mp3 形式で用意し、下記のように audio 要素で配置します。この audio 要素自体は display: none; しちゃってもいいんですが、再生されていることがわかりやすいように表示させています。

<div class="audio">
 <audio src="audio/hee.mp3" id="heeAudio" controls="controls">
  <p>audio 要素に対応したブラウザでは「へぇ」の音声ファイルの再生が可能です。</p>
 </audio>
</div>

へぇボタンを押す度に数値を増加させる

あとは 「へぇボタン」 を押す度に、input type="range" の値を 1 ずつ足していきますが、ここは JavaScript (jQuery 使用) でやっちゃいます。

使用している JavaScript 全体でも大したコードじゃないので、まずは全部下記に記載して、個別に解説していきます。

<!-- jQueryの読み込み -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
 
<script>
// へぇボタンを押す度の処理
$(function(){
  // 最初にゲージを0にして、音声ファイルを読み込み
  $("#renge").addClass("hee0");
  var audio = $("#heeAudio")[0];
  // へぇボタンクリックごとの処理
  $("label").click(function () {
    // 押す度に range の value を 1ずつ増加させる
    num = parseInt($("#hee").val());
    add = 1;
    $("#hee").val(num + add);
    // 音声の再生
    audio.load();
    audio.play();
    // class の付与
    numC = $("#hee").val();
    cls = "hee" + numC;
    $("#renge").removeClass().addClass(cls);
  });
});
</script>

まず、ボタンを押したときに、input type="range" のスライダーを動かすための処理部分ですが、抜き出すと下記のようになります。

$("label").click(function () {
  num = parseInt($("#hee").val()); // (1)#hee の value 属性値を数値で取得
  add = 1; // (2)足す数字の設定
  $("#hee").val(num + add); // (1)と(2)を足して、#hee の value 属性に入れる
});

これで、ボタンの画像を押す度に input type="range" の value 属性値が 1ずつ増加していきます。

次に、音声再生の処理ですが、ここも抜き出すと下記のようになります。

$(function(){
  var audio = $("#heeAudio")[0]; // 音声ファイルを変数に
  $("label").click(function () {
    audio.load(); // 音声ファイルを再読み込みして
    audio.play(); // 音声ファイルを再生する
  });
});

単純に再生させるだけなら audio.play(); だけでいいんですが、それだとファイルの再生が終わるまで次の再生が行われいないため、音声ファイルの再生が終わるのを待ってボタンを押さないと、その間、「へぇ~」 って言ってくれなくなってしまいます。

なので、クリックされるごとに、audio.load(); してから、audio.play(); することで、再生終了を待たずに次の音声を再生します。

この再生に関して、Firefox はよくできていて、次の音声を再生しても、前の音声を最後までちゃんとオーバーラップして鳴らしてくれるんですが、Chrome とか、他のブラウザだと、次の音声を再生開始するときに、前の音声をキャンセルしちゃうので、いい感じにならないんですよね。

ゲージの増加は背景画像で

これをどうしようか迷ったんですけど、簡単に背景画像で対応しました。ゲージの目盛りにあたる部分 (renge_back.png) と、ゲージの値 (へぇ数に応じて増えていくライトですね) にあたる部分 (renge_back_light.png) という 2枚の背景画像を重ねて配置し、background-position プロパティでライトにあたる背景画像の位置を動かすことで表現しました。

CSS には、0 へぇ~ 20 へぇ までの背景画像 (renge_back_light.png) の位置を記述しておいて、ボタンを押す度に class 属性の値を変えて、表示を切り替えていくという方法です。CSS は下記のように単純。

まず、input type="range" を内包する、div.range と、その子要素である p 要素に、上記の通り 2枚の背景画像を設定します。

.sample #renge {
  background: url(img/renge_back_light.png) no-repeat center bottom;
  ...省略...
}
.sample #renge p {
  background: url(img/renge_back.png) no-repeat center bottom;
  ...省略...
}

この状態だと、2枚の背景画像は同じ位置で完全に重なった状態になっていますが、「renge_back.png」 はアルファチャンネル付きの PNG で半透明にしてあるので、背後にある 「renge_back_light.png」 が透けて見えている状態になります。つまりこれが、「満へぇ」 の状態ですね。

あとは、後述する JavaScript で、div.range に class 名を付与することを想定して、下記のように 「へぇ」 の数に応じた、「renge_back_light.png」 の位置を指定しておいてあげます。

300px の高さを指定した input type="range" を、20ステップに分割してありますので、1へぇ当たり、15px ずつ背景画像をずらしていけばいいってことになります。

/* へぇ数ごとの設定 */
.sample #renge.hee0 {
background-position: center 300px;
/* 下方向に 300px ずらせば、背景画像は表示領域外で見えなくなるので、つまり 「0へぇ」 状態 */
}
.sample #renge.hee1 {
background-position: center 285px;
/* .hee0 から上に 15px ずらせば、「1へぇ」 状態で、以下同様 */
}
.sample #renge.hee2 {
background-position: center 270px;
}
... 以下略 ...

あとは、JavaScript で、input type="range" の value 属性値に応じた class 属性値を付けていきます。該当部分だけ抜き出してみると下記のような感じです。

$(function(){
  $("#renge").addClass("hee0"); // 最初にゲージを0に
  $("label").click(function () {
    numC = $("#hee").val(); // (1)range の value 属性値を取得
    cls = "hee" + numC; // (1)を使ってクラス名を生成
    $("#renge").removeClass().addClass(cls); // 今付いている class 属性値を消してから、生成した class 名を付与
  });
});

ということで、これで完成。

実際に動作するサンプルは下記で確認できます。

上記サンプルのファイル一式は下記から落とせますので適当にいじってみてください。

本当は、20回以上はボタンを押せないような処理とか加えた方がよいですが、今回はそこまでやってません。

ちなみに 「へぇ」 の音声ファイルは、ニコニコ動画に上がっていた動画から音声を抽出させてもらい、MP3 形式に変換ましたが、著作権的に微妙な感じもしつつもフェアユースの範囲ってことでそこはひとつよしなに。

関連エントリー

参考リンク

バンダイ 1/1 へぇボタン
バンダイ 1/1 へぇボタン

Recent Entry

全ての記事一覧を見る

Hot Entry

逆引きおすすめエントリー