最近のトグルボタン実装を少し考えてみる
この記事は賞味期限切れです。(更新から1年が経過しています)
最近ではIE6/7対応がほとんど無くなり、泥臭い手法を取る必要が少し減ってきました。 様々な場面で頻出するトグルボタンUIもまた、以前に比べて少しモダンな形での実装が可能になってきています。
隣接セレクタを使用したトグルボタン
IEはバージョン8から隣接セレクタが使えるようになります。 ここでは、その隣接セレクタとラジオボタンを使ってトグルボタンを作ってみます。 ラジオボタンをチェックボックスに変更すれば複数選択可能なボタンが表現できます。
要点は、下記の通りです。
- :checked 擬似クラスと隣接セレクタ(+)を使用
- input要素は非表示にして、隣接する span.label 要素をボタンのように見せる
- label 要素でラップして選択出来るようにする
ところが、このコードは次に挙げる問題によりIE8では正常に動作しません。
非表示のラジオボタン/チェックボックスの選択が出来ない
IE8以下では、display:none や visibility:hidden で非表示にしたinput要素を選択する事ができません。 これは関連付けられた label 要素をクリックしても同様です。 選択出来ないというのはつまり、checked 属性もつかなければ、changeイベントも発火しないという事です。
そこで、display/visibility を使わずに opacity を使用して非表示にします。
.toggle-button input[type=radio] {
position: absolute;
opacity: 0;
filter: alpha(opacity=0);
outline: none;
}
:checked の使用
IE8は隣接セレクタは使えますが、:checked 擬似クラスには対応していません。 その為、代替として選択状態の物に checked クラスを付与して使用します。
.toggle-button .checked + .label {
background-color: magenta;
color: #fff;
}
そして、input要素の選択状態と checked クラスを同期する為に次のような処理を追加してやります。
$(document).on("change", "input[type=radio], input[type=checkbox]", function(){
$(document.getElementsByName(this.name)).each(function(){
$(this).toggleClass("checked", this.checked);
});
});
このコードは、input要素の選択状態が更新されるたびに、 同じnameを持ったinput要素の checked クラスの有無を、その選択状態によって更新します。
さらに注意が必要なのは、次のような書き方が出来ない点です。
.toggle-button :checked + .label,
.toggle-button .checked + .label {
/* ここの指定はIE8で無視される */
}
一見問題なさそうですが、:checked 非対応のIE8ではこのセレクタ内のスタイル指定は無視されてしまいます。
.checked と :checked はJavaScriptで同期されているので .checked の指定だけで良しとするか、 どうしても :checked の指定も記述したい場合は分離して指定する必要があります。
.toggle-button :checked + .label { ... }
.toggle-button .checked + .label { ... }
最終的なコード
(おまけ)IE11のエミュレーションでの表示不具合
IE11の開発ツールのエミュレーション機能でIE8を選択して上のコードを確認すると、 隣接セレクタまわりの表示更新が上手くされずに、少しおかしな挙動を見せます。
- ボタンをクリックしてもボタンのスタイルが更新されない
- 前に選択されていたボタンがきちんとトグルされない
ちなみにマウスオーバーするとようやくボタンのスタイルが更新されたりします。
ネイティブのIE8はもちろん、IE10迄のブラウザモード切替でも正常に動作するのでさしたる問題ではないですが、 動作確認がちょっと捗らなくなるので、そういう事があるのだと知っておくと良いと思います。
コメント