💡

使いやすさを目指してトグルボタンを作成した

2022/09/18に公開

tl;dr

以下を調節できるようにし、それ以外は自動で決定するようにしました。

  • 全体のwidth
  • 全体のheight
  • 全体と丸の隙間(全体のpadding)

上から順に、

  1. 標準
  2. widthを大きくした
  3. heightを大きくして、widthをそれに合うようにした
  4. 3のものに加えてpaddingを小さくした
  5. paddingを0にした(calcで使用するため0ではなく0remにしている。
  6. paddingをマイナスにした

使う際のtips

  • 単位はremにしていますが、適宜変更可能です。
  • widthを--switchWidth: calc(var(--switchHeight) * 2);のようにすれば、横幅もいい感じに自動調整できます。
  • paddingをマイナスにするとはみ出ますが、親要素から飛び出る可能性があります。その場合は少し使いづらいと思いますので注意してください。

コピペ用コード

{/* reactを使用しているためclassNameだが、普通はclass */}
<div className="toggleButton">
    <input id="toggle" type="checkbox" />
	
    {/* reactを使用しているためhtmlForだが、普通はfor */}
    <label htmlFor="toggle" />
</div>
.toggleButton {
  // 標準の四角形のチェックボックスを消す。
  input {
    display: none;
  }

  --switchHeight: 2rem;
  --switchWidth: 3.6rem;
  // 外側と丸の隙間
  --switchPadding: 0.2rem;
  
  // 自動で決定される
  --circleSize: calc(var(--switchHeight) - var(--switchPadding) * 2);

  label {
    display: inline-block;
    cursor: pointer;
    position: relative;
    width: var(--switchWidth);
    height: var(--switchHeight);
    border-radius: var(--switchHeight);

    background: #ccc;
    transition: 0.4s;

    &:after {
      cursor: pointer;
      content: '';
      position: absolute;
      left: var(--switchPadding);
      top: 0;
      bottom: 0;
      margin: auto;

      width: var(--circleSize);
      height: var(--circleSize);
      border-radius: 50%;
      
      // 影は適当。丸がはみ出ない場合は影を消したほうが、よりマテリアルデザイン風でいいかもしれない
      box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);

      background: #fff;
      transition: 0.4s;
    }
  }

  input:checked {
    + label {
      background-color: #4bd865;

      &:after {
        left: calc(
          var(--switchWidth) - var(--circleSize) - var(--switchPadding)
        );
      }
    }
  }
}

そもそもなぜチェックボックス自体を隠しているのにトグルできるのか

inputとlabelを紐付ける。inputのidとlabelのforを同じ名前にすることがポイントです。これをすることで、labelの部分をクリックでinputのチェックも切り替わるようになります。疑似要素のクリックでも動くのは、おそらくイベントがlabel自体にも伝搬しているからだと思います。

僕の作った物に限らず、殆どは同じ仕組みです。

Discussion