【CSS】transitionを使ってトグルを作ってみよう!
はじめに
スマホの設定項目のオン・オフを切り替えるスイッチのような部品には、「トグル(toggle)」という名前がついています。
こういうやつです。
名前は知らなくても、「あ~これね!」となるのではないでしょうか。名前は私も最近まで知りませんでした(ググるのに時間を要しました)。
スマホだけでなく、Webページでもトグルを実装しているサイトはたくさんありますよね。ダーク・モードとライト・モードに切り替えるトグル等、よくみかけると思います。
まさに、そのダーク・モードとライト・モードを切り替えるトグルをこのサイトに実装しようとしたのですが、、、残念ながら、Reactのコンポーネント単位で背景色や文字色を指定しまっているため、実装にはCSSの抜本的な見直しが必要なことが分かり、ペンディングしてしまいました。
しかし、トグル自体は実装出来たので、今回はその方法を紹介します。
前回、アコーディオンの作り方を紹介した際は、transitionの使い方はサラッとしていましたので、今回はもう少し踏み込んで解説していきたいと思います。
この記事で作成するサンプルはgithubにも載せてあるので、参考にしてください。
前提知識
HTMLとCSSの入門的な知識はあることを前提に記載しています。といっても、HTMLはdiv要素しか使いませんし、CSSもpositionのabsoluteとrelativeや、topのような位置指定要素が分かれば問題ありません。
アニメーションに使うtransitionに関しては、基本的な使い方は解説を入れます。
JavaScriptはquerySelectorやaddEventListenerの使い方が分かればOKです。前回のアコーディオンの内容とほぼ同じです。
まずはアニメーションなしで実装!
順を追って、まずはアニメーションなしでサンプルを作ってみます。
バー(棒)の部分
トグルをバー(棒)とボール(玉)に分けて説明します。何を言ってるんだ?と思われるかもしれませんが、伝わるでしょう?
何はともあれ、下の画像のような「バー」を作ります。左下のグレー部分です。
HTML
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="main.css">
<title>トグル</title>
</head>
<body>
<div class="bar"></div>
</body>
</html>
バー部分は、barクラスのdivタグです。CSSはlinkタグで同階層にあるmain.css
を指定しています。
CSS
main.css
.bar {
width: 50px;
height: 26px;
border-radius: 13px;
background-color: lightgray;
position: relative;
}
バーの幅と高さをそれぞれwidthとheightで指定しています。小さい部品ですので、固定値で良いと思います。ここは好みなので、適宜調整してください。
border-radiusで、角を丸くしています。heightの半分の値にすると、ちょうど丸を半分に切ったような形になります。ここも好みが出るところかと思うので、変えたい方はリンクのドキュメントを確認して他の値を設定してみてください。
このあとに作るボール部分の位置は、「バーからの相対位置」で指定する必要があります。そのため、position: relative
を設定しています。
ボール(玉)の部分
今度は下の画像のような「ボール」部分を付け加えます。
html
headタグ部分は変更がないため省略しています。
index.html
<body>
<div class="bar">
<div class="ball"></div>
</div>
</body>
ボール部分となるdiv要素(ballクラス)を、バー部分のdivの中に入れてあります。
CSS
追加したballクラスのみ記載しています。
main.css
.ball {
position: absolute;
top: 2px;
left: 2px;
width: 21px;
height: 21px;
border-radius: 10.5px;
background-color: white;
}
position: absolute
にしてあります。これにより、topとleftは、「親要素(position: relative
のバー)の左上からの位置」になります。
完全な丸にするために、widthとheightを同じ値にし、border-radiusにはその半分の値を指定しています。
今回は上の画像のように、ボールがバーの枠内に収まるよう、ボールの大きさや位置を調整してみました。逆に、バーより少し大きくして、左側が少しはみ出でいるデザインもカッコいいと思います。
今回は、このままバーより小さいスタイルで行きますが、後で好みに調整してみてください。
「オン」の状態を作る
今までの状態を「オフ」だとします。今度は、下の画像のような「オン」の状態を作ります。
なお、オンとオフは後でJavaScriptで切り替えを行いますので、その想定で作ります。
CSS
先にcssを見てみます。bar-onクラスとball-onクラスを追加しています。
main.css
.bar {
width: 50px;
height: 25px;
border-radius: 12.5px;
background-color: lightgray;
position: relative;
}
.ball {
position: absolute;
top: 2px;
left: 2px;
width: 21px;
height: 21px;
border-radius: 10.5px;
background-color: white;
}
.bar-on {
background-color: #555;
}
.ball-on {
left: 27px;
}
bar-onクラスは背景色のみ指定、ball-onクラスは、左側からの位置のみしています。最終的にはJavaScriptで、これら2つのCSSを付けたり外したりすることでオン・オフの表示を切り替えていきます。
html
index.html
<body>
<div class="bar bar-on">
<div class="ball ball-on"></div>
</div>
</body>
bar-onクラスをバーに追加し、ball-onクラスをボールに追加しています。
これで、上の画像のような「オン」の状態になります。
JavaScriptでオン・オフを切り替えよう
今度は、下の動画のようにクリックでオン・オフが変わるようにします。動画にはタップした箇所も記録されていますが、気にしないでください。
html
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="main.css">
<srcipt src="main.js"></srcipt>
<title>トグル</title>
</head>
<body>
<div class="bar">
<div class="ball"></div>
</div>
</body>
</html>
さきほどの例で「オン」の状態を作りましたが、デフォルトでは「オフ」の状態にしたいので、ball-onクラスとbar-onクラスを外しておきます。
JavaScriptのファイル名はmain.js
にしました。headタグのscriptタグで指定しています。
JavaScript
上述のとおり、JavaScriptでCSSを切り替えることで、オン・オフの切り替えを実現しています。
トグルのオン・オフに応じて適用されるクラスは以下のとおりです。
- オフ:バーはbarのみ、ボールはballのみ
- オン:バーはbarとbar-on、ボールはballとball-on
htmlのscriptタグで指定したJavaScriptは、上記を踏まえて以下のように作ります。
main.js
function main() {
// 「バー」(barクラスの要素)
const bar = document.querySelector(".bar")
// 「ボール」(ballクラスの要素)
const ball = document.querySelector(".ball")
// オン・オフの状態
let isOn = false
// バーをクリックした時の動作
bar.addEventListener("click", () => {
// オン⇔オフを切替
isOn = !isOn
// バーのスタイル
let barStyle = "bar"
// ボールのスタイル
let ballStyle = "ball"
// "オン"の場合、bar-onとball-onスタイルを追加
if (isOn) {
barStyle += " " + "bar-on"
ballStyle += " " + "ball-on"
}
// スタイルを適用
bar.className = barStyle
ball.className = ballStyle
})
}
window.addEventListener("load", main)
前回紹介したアコーディオンと非常に似ています。
まず最下段のwindow.addEventListener("load",main)
で、ブラウザがCSS等すべてのリソースが読込が終わった後にmain関数を実行するようにしています。
見慣れない方はWindow: load イベントをご確認ください。
main関数では、document.querySelector
でバー部分とボール部分のdiv要素をそれぞれ取得しています。そして、トグルのオン・オフはisOn
変数で制御しています。trueならオン、falseならオフです。初期表示時はオフにしています。
そして、bar.addEventListener
でバーのクリック時の処理を登録しています。バーがクリックされると、まずisOn
を反転させます。isOn
がtrueの場合、バーとボールそれぞれに、bar-onとball-onのクラスを追加しています。逆にfalseの場合、bar-onとball-onは追加されないようになっています。
これで、オン・オフに応じた表示に切り替えるJavaScriptは完成です!
アニメーションをつけるぞ!
ここまでは、オンとオフの切り替え時に特段アニメーションを付けていませんでした。
多くの場合、ボールの動き等にアニメーションが付いています。試しに、スマホの設定画面でトグルを触ってみてください。ボールは左右にスライドするようなアニメーションがついていると思います。
今回はCSSのtransitionプロパティを使って、ボールのスライドと、背景色の変更にアニメーションをつけてみます。
transitionプロパティ
transitionは、リンクのMDNのドキュメントには、以下のように記載がされています。
要素の 2 つの状態間の変化を定義するためのものです。それぞれの状態は :hover や :active のような擬似クラスで定義されたり、 JavaScript を使用して動的に設定されたりします。
「何かのCSSのプロパティの値の変化」(何秒かけて変化させるか、何秒待ってから変化させるか、変化の加速度をどうするか)を定義することができるもの、と私は理解しています。
なおtransitionプロパティは、transition-delay、transition-behavior、transition-duration、transition-property、transition-timing-functionの一括指定プロパティとなります。そのため、値の指定の仕方は、使うプロパティによって異なります。今回使うのは、transition-propertyとtransition-durationです。この2つを指定する場合、transition: プロパティ名 秒数s
のように指定をします。
なお、transitionに指摘ができないプロパティ(display、position、overflow等)もあります。
ここで、ここまでで作ったcssを確認してみます。transitionに関係しないプロパティは一部省略しています。
.bar {
/* 一部略 */
background-color: lightgray;
}
.ball {
/* 一部略 */
left: 2px;
}
.bar-on {
background-color: #555;
}
.ball-on {
left: 27px;
}
バー部分は、オフ時はbackground-color: lightgray
で、オン時はbackground-color: #555
です。ボール部分はオフ時はleft: 2px
、オン時はleft: 27px
です。それぞれ、同じプロパティの値が変わっています。
transitionにこれらのプロパティを指定することで、変化にかかる秒数(transition-duration)等を指定することができます。
transitionを追加
状態が変化しているのは、バーのbackground-colorと、ボールのleftでした。それぞれ、transitionにこのプロパティを指定すればOKです。今回の例では、変化にかかる秒数は、「0.3s(秒)」にします。
main.css
.bar {
width: 50px;
height: 25px;
border-radius: 12.5px;
background-color: lightgray;
position: relative;
/* 追加:background-colorの変化は0.3秒かける */
transition: background-color 0.3s;
}
.ball {
position: absolute;
top: 2px;
left: 2px;
width: 21px;
height: 21px;
border-radius: 10.5px;
background-color: white;
/* 追加: leftの変化は0.3秒かける */
transition: left 0.3s;
}
.bar-on {
background-color: #555;
}
.ball-on {
left: 27px;
}
barクラスにtransition: background-color 0.3s
、ballクラスにtransition: left 0.3s
を追加しています。これにより、barクラスのbackground-colorの変化は0.3秒、ballクラスのleftの変化は0.3秒かかることになります。
これで動かしてみましょう。
ちゃんとボールがスライドしてますし、バーの背景色も徐々に変化してますね!
背景色の変化の代わりに、borderの色や太さや、ボールの色を変化させても面白いかもしれません。
最後に
今回は、CSSのtransitionを使って、トグルを作成する方法を紹介しました。他にも様々なデザインがありますので、ボールの大きさや形を変えたり等、色々試してみると面白いと思います。【コピペOK!】ON/OFFスイッチのデザイン7個|iOS風スイッチもあるよ!にたくさんサンプルがあるので、ご参考にリンクを共有します。
後、今回は触れられていませんが、「どっちがオンでどっちがオフか?」分かるように、見出しをつけたりする工夫も大切かと思います。
私も、いずれダーク・モード切り替えのトグルにリベンジしたいですね。