【CSS】CSSの擬似クラス :toggle()を使ってToggle Switchを作る

## 概要
みなさんは、CSS Toggles`:toggle()`という擬似クラスをご存知でしょうか？

実は、2022年4月28日に Tab Atkins Jr. (Google)とMiriam E. Suzanne (Invited Expert)によって、
CSS Toggles`:toggle()`という、CSSだけでON/OFFの値に応じて、スタイルを変更する機能の草案が提出されました。

今回は、このCSS Togglesの機能を使って、Toggle Switchを作ってみました。

CSS Togglesの詳しい機能については以下の記事でまとめたので、ご一緒にご覧ください。

https://qiita.com/degudegu2510/items/ba50b662db243cea8f62

:::note warn
CSS Toggles`:toggle()`はまだ公式に提案するための草案のため、
この記事のデモは`JS-polyfill`を使って作成しています。ご注意ください。
:::

※ `JS-polyfill`は、平たく言うと、「Chromeでは動いたのに、IEだとこのjs動かないよー」に対処できるツール

## Toggle Switch (完成図)
Toggle Switchとは、こんな感じのコンポーネントです。
クリック（タップ）することで、CSS Togglesの値に応じて、スタイルが変更します。

<p class="codepen" data-height="300" data-default-tab="result" data-slug-hash="GRQRdpV" data-user="sp_degu" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/sp_degu/pen/GRQRdpV">
  Qiita - accordion</a> by でぐぅー | Qiita (<a href="https://codepen.io/sp_degu">@sp_degu</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## :toggle()を使ったToggle Switchの作り方
**作り方の概要**

1. Toggle Switchのスタイル・見た目を作成する。
2. CSS Togglesを使うことを宣言する。
3. 要素をクリック（タップ）することで、CSS Togglesの値を変える。
4. CSS Togglesの値に応じて、Toggle Switchのスタイル・見た目を変える。
5. （おまけ①）いい感じにアニメーションするようにする。
6. （おまけ②）CSS Togglesの値に応じて、周りのスタイル・見た目を変える。

### ① Toggle Switchのスタイル・見た目を作成する。
#### HTML
HTMLは、こんな感じです。
`toggleWapper` で、ボタンとラベルまとめます。
`toggleButton` のidと `toggleLabel` のforの値を揃えて、`<button>`と`<label>`を紐づけます。

```main.html
<div class="toggleWapper">
  <button id="toggle" class="toggleButton"></button>
  <label for="toggle" class="toggleLabel">ダークモード<label>
</div>
```

#### CSS
CSSは、こんな感じです。 スタイルはお好みですので、カスタマイズはご自由にお願いします。

+ **toggleWapper**
    + `flex`で横並びにしています。
    + `align-item`と`justify-content`で左右上下中央に移動しています。
+ **toggleButton**
    + `width`と`height`は、`●`を基準に指定しています。
+ **toggleButton::after**
    + `::after`を用いて、Toggle Switchの`●`部分を作成しています。
+ **toggleLabel**
    + よしなに色とmarginを指定しています。

```style.css
.toggleWapper {
  display: flex;
  align-items: center;
  justify-content: center;
}

.toggleButton {
  width: 46px;
  height: 24px;
  position: relative;
  border: none;
  border-radius: 12px;
  background-color: #BCBDBD;
  cursor: pointer;
}

.toggleButton::after {
  content: "";
  position: absolute;
  width: 20px;
  height: 20px;
  border-radius: 100%;
  left: 1px;
  top: 1px;
  background: #FFFFFF;
  border: 1px solid #BCBDBD;
}

.toggleLabel {
  color: #1E2121;
  margin-left: 12px;
  cursor: pointer;
}
```

#### CodePenで実装するとこんな感じになります
<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="rNJxNZX" data-user="sp_degu" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/sp_degu/pen/rNJxNZX">
  Qiita - :toggle() ①</a> by でぐぅー | Qiita (<a href="https://codepen.io/sp_degu">@sp_degu</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
※ スタイルを当てただけになるので、まだ動きません。

### ② CSS Togglesを使うことを宣言する。
CSS Toggles`:toggle()`を使うために値（変数？）を宣言します。
宣言する場所は、CSS Togglesを使いたい親要素か兄弟要素になります。

今回の場合は、`toggleButton`の`::after`で`●`を動かしたいので、
`toggleWapper`で宣言します。

`toggle-root: darkmode;`と宣言して、`darkmode`を使って
CSS Togglesを操作していきます。

```style.css
.toggleWapper {
  display: flex;
  align-items: center;
  justify-content: center;
  toggle-root: darkmode;
}
```

※ `toggle-root`の詳しい解説は[こちらから](https://qiita.com/degudegu2510/items/ba50b662db243cea8f62)

### ③ 要素をクリック（タップ）することで、CSS Togglesの値を変える。
②で宣言した`darkmode`の値を変えるために、
`toggle-trigger`というプロパティをクリック（タップ）したい要素に追加します。

今回の場合は`toggleButton`をクリック（タップ）した時に`darkmode`の値を変更します。

```style.css
.toggleButton {
  width: 46px;
  height: 24px;
  position: relative;
  border: none;
  border-radius: 12px;
  background-color: #BCBDBD;
  cursor: pointer;
  toggle-trigger: darkmode;
}
```

※ `toggle-trigger`の詳しい解説は[こちらから](https://qiita.com/degudegu2510/items/ba50b662db243cea8f62)

### ④ CSS Togglesの値に応じて、Toggle Switchのスタイル・見た目を変える。
擬似クラス`:toggle()`を用いることで、②で宣言した`darkmode`の値に応じて
スタイル・見た目を変えることができます。

今回の場合は、`darkmode`の値が１になったら、

- `toggleButton`の背景を`#BCBDBD`→`#55C500`に変わる
- `toggleButton`の`::after`の場所・色を変える

ことをします。

```style.css
.toggleButton:toggle(darkmode) {
  background-color: #55C500;
}

.toggleButton:toggle(darkmode)::after {
  border-color: #55C500;
  transform: translateX(100%);
}
```

これを記載することでこんな感じになります。
<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="zYRrxmw" data-user="sp_degu" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/sp_degu/pen/zYRrxmw">
  Qiita - :toggle() ②</a> by でぐぅー | Qiita (<a href="https://codepen.io/sp_degu">@sp_degu</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>


### ⑤ （おまけ①）いい感じにアニメーションするようにする。
`toggleButton`の`::after`に`transition`を追加することで
いい感じトランディションするように設定します。

```style.css
.toggleButton::after {
  content: "";
  position: absolute;
  width: 20px;
  height: 20px;
  border-radius: 100%;
  left: 1px;
  top: 1px;
  background: #FFFFFF;
  border: 1px solid #BCBDBD;
  transition: all 0.1s ease 0s;
}
```
### ⑥ （おまけ②）CSS Togglesの値に応じて、周りのスタイル・見た目を変える。
今回は、Toggle Switchだけではなく、周りのスタイル・見た目を変えて、
ダークモードに変更している風にするため、その対応をおこないます。

基本的には、擬似クラス`:toggle()`を使って、それぞれの要素のスタイル・見た目を変えます。

今回対応するのは、

+ `toggleWapper`の背景を変える
+ `toggleLabel`のcolorを変える
+ ついでに`toggleWapper`を画面いっぱいにしてToggle Switchを画面の中央に移動する

ことをします。

```style.css
.toggleWapper {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100vw;
  height: 100vh;
  background-color: #ffffff;
  toggle-root: darkmode;
}

.toggleWapper:toggle(darkmode) {
  background-color: #1E2121;
}

.toggleLabel:toggle(darkmode) {
  color: #FFFFFF;
}

```

こんな感じに記載すると完成！！！！ 🎉

<p class="codepen" data-height="300" data-default-tab="result" data-slug-hash="GRQRdpV" data-user="sp_degu" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/sp_degu/pen/GRQRdpV">
  Qiita - accordion</a> by でぐぅー | Qiita (<a href="https://codepen.io/sp_degu">@sp_degu</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## まとめ
この記事では、このCSS Togglesの機能を使って、Toggle Switchを作ってみました。

今まではcheckboxの`:checked`を使ってスタイルを変え、
checkboxを`display: none;`にしていました。

そうすると、表示しないDOMを書くことになるので、
セマンティック的にも、SEO的にも嬉しくないです。

まだ、CSS Togglesは素案ですが、早くリリースされるのを楽しみにしています。

---

最後まで読んでくださってありがとうございます！

普段はデザインやフロントエンドを中心にQiitaに記事を投稿しているので、ぜひQiitaのフォローとX(Twitter)のフォローをお願いします。

https://twitter.com/degudegu2510

### Ref
https://qiita.com/degudegu2510/items/ba50b662db243cea8f62

https://tabatkins.github.io/css-toggle/

https://github.com/oddbird/css-toggles

https://toggles.oddbird.net/