スマホアプリのコーディングをしていた時、
設定画面であるようなON/OFFのチェックボックスをCSSで作った時のサンプルと、
その際iOSで発生したバグの対処法まとめです。

目次
  1. inputタグとlabelタグとの関連付け
  2. CSSで作ってみたON/OFFのサンプル
  3. iOSで発生したバグについて

inputタグとlabelタグとの関連付け

labelタグを関連付けると、ラベルのクリックでもフォーム部品を選択したことになりますが、
その方法は2つあります。

for+idを使う

labelタグにfor=””、inputタグにid=””を加えて、それぞれ同じ名前にする方法です。

<input type="radio" value="ゴリラ" id="gorilla">
<label for="gorilla">ゴリラ</label>

labelタグでinputタグを囲む

関連付けたいlabelタグでinputタグを囲むことで関連付けることもできます。

<label>
  <input type="radio" value="ゴリラ">ゴリラ
</label>

2つ方法がありますが、後者の方が好きです。

簡単というのもありますが、前者だと関連付けるだけのためにid付ける必要があるので、あんまりやりたくないです。

後者はIE6以下は対応してないらしいですが、
もうあんまり気にしなくていいですかね。

ってことで、後者の方で以下書きます。

CSSで作ってみたON/OFFのサンプル

シンプルなものですが、アプリの設定画面であるようなON/OFFのサンプルを作りました。

ON/OFFに合わせて、スイッチが切り替わるようなものです。

ソースコードはこちら

HTML
<label class="setting">
    <input type="checkbox" checked>
    <span class="on">ON</span>
    <span class="off">OFF</span>
</label>
CSS
label {
    display: block;
    box-sizing: border-box;
    position: relative;
    width: 200px;
    height: 60px;
    margin: 0 auto;
    padding: 8px;
    border: 1px solid #999;
    border-radius: 30px / 50%;
}
label::after {
    content: "";
    clear: both;
    display: block;
}
input[type="checkbox"] {
    display: none;
}
label span {
    display: block;
    float: left;
    width: 50%;
    height: 44px;
    line-height: 44px;
    text-align: center;
    transition-duration: .3s;
}
label input[type="checkbox"] + span::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 50%;
    z-index: -1;
    width: 90px;
    height: 50px;
    margin: auto;
    border-radius: 25px / 50%;
    background-color: #333;
    transition-duration: .2s;
}
label input[type="checkbox"]:checked + span::before {
    left: 8px;
}
label input[type="checkbox"] + span,
label input[type="checkbox"]:checked + span + span {
    color: #999;
}
label input[type="checkbox"]:checked + span,
label input[type="checkbox"] + span + span {
    color: #fff;
}

positionの代わりにtranslateを使う

また、上記はスイッチの移動にpositionのleftを使っていますが、
translateを使うと少し滑らかな動きになります。

PCでは分かりにくいですが、スマホで見ると分かるかと思います。

[translate]

比較用[position使用]

少しですがスイッチの移動が滑らかになっています。

CSSの記述はこちら

.setting_input label input[type="checkbox"] + span::before {
  content: "";
  display: block;
  position: absolute;
  top: 4px;
  z-index: -1;
  width: 90px;
  height: 50px;
  border-radius: 25px / 50%;
  background: #333;
  -webkit-transform: translateX(90px);
  transform: translateX(90px);
  transition-duration: .3s;
}
.setting_input label input[type="checkbox"]:checked + span::before {
  -webkit-transform: translateX(0%);
  transform: translateX(0%);
}

なぜ滑らかになるかは以下の記事が参考になります。

Web制作にGPU処理を取り入れる

iOS8.xで発生したバグについて

先ほどのサンプルですが、タップに合わせてスイッチが切り替わるような動きと
ON/OFFに合わせてテキストの色も切り替えています。

が、iOS8.xではOFFのテキストの色が変わらないです…。
iOS9.x台では直っているようです。

かなり謎いバグで、ググり方すら分からず試行錯誤してると、
どうもinputタグの隣接セレクタで2つ目以降はスタイルがあたらないようです。

ここの部分

label input[type="checkbox"] + span,
label input[type="checkbox"]:checked + span + span {
    color: #999;
}
label input[type="checkbox"]:checked + span,
label input[type="checkbox"] + span + span {
    color: #fff;
}

Android4.4は動いていました。それ以外は確認していません。

間接セレクタで解決した

隣接セレクタで動かなかったので間接セレクタというものを使いました。

CSSの該当の箇所を以下に変更。

label input[type="checkbox"] + span,
label input[type="checkbox"]:checked ~ .off {
    color: #999;
}
label input[type="checkbox"]:checked + span,
label input[type="checkbox"] ~ .off {
    color: #fff;
}

修正後のサンプルがこちら

さいごに

今回、間接セレクタで対処しましたが、他にも方法はあるようです。

以下の記事を参考にしました。

:checked擬似クラスの隣接セレクターのWebkit系での挙動とか

iOS8以前の対応が必要で、同じような挙動が発生するときに疑ってみるといいかもしれません。

Tweet
このエントリーをはてなブックマークに追加
Pocket