Mach3.laBlog

ラジオボタンでグラフィカルなトグルボタンを作ってみる

この記事は賞味期限切れです。(更新から1年が経過しています)

HTMLでトグルボタンを実装するにはinput[type=radio]が近道ですが、 リッチな雰囲気にする為に見た目を制御したい。今回はそんなお話です。

ラジオボタンでグラフィカルなトグルボタンを作ってみる

ラジオボタンでグラフィカルなトグルボタン

「ラジオボタンがすでにグラフィカルでは?」という細かいつっこみは置いといて頂き、 本稿ではより自由度高く外見をカスタマイズする方法を記していきます。

ラジオボタンでなくともトグルボタンはJavaScriptで作れますが、 択一で選択する仕組みをわざわざ自前で実装するよりも、 その為に作られた物をその為に使って実現してみます。

マークアップ

例えばこんなHTMLとCSSを書きます。 血液型を選択する簡単なトグルボタンです。

血液型を選択する簡単なトグルボタン

HTML

<form class="question">
    <h1>あなたの血液型は?</h1>
    <ul class="bloodtype-list">
        <li><label><input type="radio" name="bloodtype" value="A" checked />A</label></li>
        <li><label><input type="radio" name="bloodtype" value="B" />B</label></li>
        <li><label><input type="radio" name="bloodtype" value="O" />O</label></li>
        <li><label><input type="radio" name="bloodtype" value="AB" />AB</label></li>
    </ul>
</form>

CSS

/**
 * 重要な箇所のみ抜粋
 */

.bloodtype-list label input {
    display:none;
}
.bloodtype-list label {
    /* 非選択時のスタイル */
}
.bloodtype-list label.selected {
    /* 選択時のスタイル */
}

label>input という構造にして、inputをdisplay:none;で隠してしまいます。 選択されたラジオボタンのlabelに「selected」クラスが付加されれば、選択状態を表現できまね。 その部分は、JavaScriptにお任せします。

JavaScript

jQueryを使います。非常に単純な処理です。

var radios = $("input[name=bloodtype]");

radios.on("change", function(e){
    // 一旦全てのlabel要素からselectedクラスを除去
    radios.closest("label").removeClass("selected");
    // 選択されたラジオボタンの親のlabelにselectedクラスを設定
    $(e.target).closest("label").addClass("selected");

    // 選択変更時に何かしたければここで
    console.log("Changed to " + e.target.value);
});


// 選択状態を初期化する
radios.filter(":checked").trigger("change");

これで概ね動くのですが、IE8以下はもう一工夫必要です。

旧IE対策

IE8以下は、非表示にしているラジオボタンのlabel要素をクリックしても 選択状態は変わらず、changeイベントも発火しない様子です。

なので、その挙動を簡単にエミュレートしてあげます。

radios.closest("label").on("click", function(e){
    var input = $(this).find("input");
    if(! input.prop("checked")){
        input.prop("checked", true).trigger("change");
    }
});

親のlabel要素をクリックした時に、子のinput要素が選択されていなければ、 checkedにしてchangeイベントに着火します。

jQueryプラグインにまとめてみる

一連の動作をプラグインにまとめてみました。

$.fn.extend({
    toggleButtons : function(callback){
        var radios = this;
        radios.on("change", function(e){
            radios.closest("label").removeClass("selected");
            $(e.target).closest("label").addClass("selected");
             callback.call(this, e);
        });
        radios.closest("label").on("click", function(e){
            var input = $(this).find("input");
            if(! input.prop("checked")){
                input.prop("checked", true).trigger("change");
            }
        });
        radios.filter(":checked").trigger("change");
    }
});

使い方

引数のcallbackは、選択状態が変更された時にコールされます。

$("input[name=bloodtype]").toggleButtons(function(e){
    // 選択変更時に何かする
    console.log("Changed to " + e.target.value);
});

デモ

JSBinにデモを用意しました。

まとめ

あとはlabelとlabel.selectedの見た目を存分にデザインしてあげましょう。 CSS3で記述するもよし、画像置換するもよし、子にimgを入れて差し替えてもよし。 お好みのコースで心ゆくまでごゆっくりと。


2013/06/22
checkedにあわせて選択するようにコードを調整

コメント

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です


*

くろねこ3378daa332b62c858ec1539b16ea0bf5
<p>早々の回答ありがとうございます!
非常に助かります。radios.filter(":checked")とするのですね、勉強不足でした。コメントしてよかったです。</p>
mach32ac00a19d261ed2dfb9c3434899a1ce9
<p>今までの内容ですと一番初めの要素を自動選択していましたが、先程 checked されたものを選択するように変更を行いました。こちらで如何でしょうか。</p>
くろねこ3378daa332b62c858ec1539b16ea0bf5
<p>こちらのデモを参考にさせて頂き、非常にありがたく思っております。1つ質問をさせてください。
例えば、デフォルトで「O型」を選択状態にするには、どのようにすればよろしいでしょうか?
回答のほど、よろしくお願い致します。</p>
mach32ac00a19d261ed2dfb9c3434899a1ce9
<p>選択状態の初期化の <code>radios.filter(":first").trigger("change");</code> の箇所を削除すれば、希望される動作になると思います。</p>
snowman7bd3f70a4ab6bc4545fb0104fd3a66b5
<p>こちらのデモを参考に作成させて頂いております。
デフォルトで「checked」されていない状態にしたいのですが、
javaの勉強不足のため分かりません…。。申し訳ないです。。
早めにご回答頂けるとありがたいです。
宜しくお願い致します。</p>