CSS3アニメーションでつくるインターフェイス表現

第13回電灯をつけたり消したりする

今回のお題は、スイッチで電灯をつけたり消したりするサンプル1⁠。デザインとアニメーション表現はlampを参考にさせてもらった。この連載の主題である「インターフェイス」としては、応用の幅が少し狭いかもしれない。けれど、おもしろい素材なので、採り上げることにした。ただ、スイッチがさびしいので、CSS3 Checkbox Stylesからひとつ使わせてもらった。複数のCSSを組み合わせる場合は、設定がかぶらないようにできるだけクラスを用いるのがよい。そこで、構成は大幅に手直しした。もちろん、コードは絞り込み、わかりやすく組み立て直している。

サンプル1 CSS3: Lamp with switch

見える要素がない<body>要素の記述

今回、HTMLドキュメントの<body>要素には、見える要素がないコード1⁠。細かくいえば、type属性が"checkbox"の<input>要素class属性"check")はある。だが、CSSでvisibilityプロパティをhiddenにして隠すコード1参照⁠⁠。つまり、電灯もスイッチもすべてCSSでつくるということだ。なお、<label>要素for属性に<input>要素のid属性値("status")を与えたので、この要素のクリックでチェックボックスのオンとオフが切り替えられる。また例によって、ベンダープレフィックスを省くため、<script>要素で-prefix-freeを読み込んである(第1回のベンダープレフィックスと-prefix-freeの項参照⁠⁠。

コード1 <body>要素には見える要素がない
<head>要素

<style>
.check {
    visibility: hidden;
}
</style>
<script src="lib/prefixfree.min.js"></script>
<body>要素
<div class="container">
    <input type="checkbox" id="status" name="check" class="check" />
    <label for="status" class="button"><div><!--button--></div></label>
    <div class="lamp">
        <div class="light"><!--light--></div>
    </div>
</div>

消えている電灯を静的に表現する

まず、<div>要素class属性"lamp")で、つぎのように電灯が下がる線を描く図1⁠。background-imageプロパティには、linear-gradient()関数を3つ定めた。ところが、(rgba(0, 0, 0, 0.7))はすべて同じだ。これは3つにそれぞれ異なる大きさbackground-sizeプロパティ)と位置background-positionを与えることで、3つのパーツを表示している。

body {
    background: #2f323c;
}
.container {
    position: relative;
    width: 100vw;
    height: 100vh;
}
.lamp {
    position: relative;
    margin: -19px auto;
    width: 0.7rem;
    height: 10rem;
    background-image: linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)),
        linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)),
        linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7));
    background-repeat: no-repeat;
    background-size: 0.15rem 8rem,
        0.4rem 0.8rem,
        0.7rem 2rem;
    background-position: 50% 0,
        0.19rem 8rem,
        0 8.8rem;
}
図1 電灯が下がる線
図1 電灯が下がる線

消えている電灯は<div>要素class属性"lamp")に、つぎのような::before擬似要素で加える図2⁠。円形にして、box-shadowプロパティで内側insetに縁を与えた。

.lamp::before {
    content: '';
    position: absolute;
    left: -1.65rem;
    bottom: -4rem;
    width: 4rem;
    height: 4rem;
    border-radius: 50%;
    background: rgba(255,255, 255, 0.03);
    box-shadow: inset 2px -2px 10px rgba(255, 255, 255, 0.07);
}
図2 消えている電灯
図2 消えている電灯

電極の細長い部分は、つぎのように別の<div>要素class属性"light")でつくる。もうひとつの丸いパーツは、::before擬似要素で加えた図3⁠。消えている電灯のCSSの定めは、以下のコード2にまとめた。

.light {
    position: absolute;
    top: 10.05rem;
    left: 0.25rem;
    height: 1.5rem;
    border-right: 0.2rem solid rgba(255, 255, 255, 0.05);
}
.light::before {
    position: absolute;
    box-sizing: border-box;
    content: '';
    top: 1.5rem;
    left: -0.35rem;
    width: 0.9rem;
    height: 0.9rem;
    border-radius: 50%;
    border: 0.2rem solid rgba(255, 255, 255, 0.05);
}
図3 電極を加える
図3 電極を加える
コード2 消えている電灯の静的なスタイル
body {
    background: #2f323c;
}
.container {
    position: relative;
    width: 100vw;
    height: 100vh;
}
.lamp {
    position: relative;
    margin: -19px auto;
    width: 0.7rem;
    height: 10rem;
    background-image: linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)),
        linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)),
        linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7));
    background-repeat: no-repeat;
    background-size: 0.15rem 8rem,
        0.4rem 0.8rem,
        0.7rem 2rem;
    background-position: 50% 0,
        0.19rem 8rem,
        0 8.8rem;
}
.lamp::before {
    content: '';
    position: absolute;
    left: -1.65rem;
    bottom: -4rem;
    width: 4rem;
    height: 4rem;
    border-radius: 50%;
    background: rgba(255,255, 255, 0.03);
    box-shadow: inset 2px -2px 10px rgba(255, 255, 255, 0.07);
}
.light {
    position: absolute;
    top: 10.05rem;
    left: 0.25rem;
    height: 1.5rem;
    border-right: 0.2rem solid rgba(255, 255, 255, 0.05);
}
.light::before {
    position: absolute;
    box-sizing: border-box;
    content: '';
    top: 1.5rem;
    left: -0.35rem;
    width: 0.9rem;
    height: 0.9rem;
    border-radius: 50%;
    border: 0.2rem solid rgba(255, 255, 255, 0.05);
}
.check {
    visibility: hidden;
}

スイッチを静的に表現する

つぎに、ボタンスイッチを描く。オフのスタイルから決めよう。オンとオフに共通の台座は、つぎのように<div>要素class属性"button")::before擬似要素として加える。円形の背景をlinear-gradient()関数により明るいグレーのグラデーションで塗り、box-shadowプロパティで立体的に見せている。オフの暗い円形の内側は、子の<div>に描いた図4⁠。

.button::before {
    content: '';
    width: 28px;
    height: 28px;
    position: absolute;
    left: 0;
    background: linear-gradient(to bottom, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%);
    border-radius: 50%;
    box-shadow: inset 0px 1px 1px white,
        0px 1px 3px rgba(0, 0, 0, 0.5);
}
.button div {
    width: 20px;
    height: 20px;
    cursor: pointer;
    position: absolute;
    left: 4px;
    top: 4px;
    background: linear-gradient(to bottom, #222222 0%, #45484d 100%);
    border-radius: 50%;
}
図4 オフのボタンスイッチ
図4 オフのボタンスイッチ

ボタンスイッチのオンの内側は、子の<div>要素に::after擬似要素でつぎのように加える。box-shadowプロパティで出っ張りを表現した図5⁠。アニメーションさせる前の電灯とスイッチは整ったので、以下のコード3にまとめた。

.button div::after {
    content: '';
    width: 16px;
    height: 16px;
    position: absolute;
    top: 2px;
    left: 2px;
    background: #27ae60;
    background: linear-gradient(to bottom, #27ae60 0%, #145b32 100%);
    border-radius: 50%;
    box-shadow: inset 0px 1px 1px white,
        0px 1px 3px rgba(0, 0, 0, 0.5);
}
図5 オンのボタンスイッチ
図5 オンのボタンスイッチ
コード3 ボタンスイッチと電灯の静的なスタイル
body {
    background: #2f323c;
}
.container {
    position: relative;
    width: 100vw;
    height: 100vh;
}
.lamp {
    position: relative;
    margin: -19px auto;
    width: 0.7rem;
    height: 10rem;
    background-image: linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)),
        linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)),
        linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7));
    background-repeat: no-repeat;
    background-size: 0.15rem 8rem,
        0.4rem 0.8rem,
        0.7rem 2rem;
    background-position: 50% 0,
        0.19rem 8rem,
        0 8.8rem;
}
.lamp::before {
    content: '';
    position: absolute;
    left: -1.65rem;
    bottom: -4rem;
    width: 4rem;
    height: 4rem;
    border-radius: 50%;
    background: rgba(255,255, 255, 0.03);
    box-shadow: inset 2px -2px 10px rgba(255, 255, 255, 0.07);
}
.light {
    position: absolute;
    top: 10.05rem;
    left: 0.25rem;
    height: 1.5rem;
    border-right: 0.2rem solid rgba(255, 255, 255, 0.05);
}
.light::before {
    position: absolute;
    box-sizing: border-box;
    content: '';
    top: 1.5rem;
    left: -0.35rem;
    width: 0.9rem;
    height: 0.9rem;
    border-radius: 50%;
    border: 0.2rem solid rgba(255, 255, 255, 0.05);
}
.button::before {
    content: '';
    width: 28px;
    height: 28px;
    position: absolute;
    left: 0;
    background: linear-gradient(to bottom, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%);
    border-radius: 50%;
    box-shadow: inset 0px 1px 1px white,
        0px 1px 3px rgba(0, 0, 0, 0.5);
}
.button div {
    width: 20px;
    height: 20px;
    cursor: pointer;
    position: absolute;
    left: 4px;
    top: 4px;
    background: linear-gradient(to bottom, #222222 0%, #45484d 100%);
    border-radius: 50%;
}
.button div::after {
    content: '';
    width: 16px;
    height: 16px;
    position: absolute;
    top: 2px;
    left: 2px;
    background: #27ae60;
    background: linear-gradient(to bottom, #27ae60 0%, #145b32 100%);
    border-radius: 50%;
    box-shadow: inset 0px 1px 1px white,
        0px 1px 3px rgba(0, 0, 0, 0.5);
}
.check {
    visibility: hidden;
}

スイッチと点灯のアニメーションを加える

今回のお題では、見えるものがない<body>要素に、CSSで電灯とスイッチを描くのがもっとも手間のかかる作業だった。これから加えるアニメーションは、それと比べれば簡単だ。ボタンスイッチのアニメーションから先につくろう。ボタンスイッチのオンの::after擬似要素は、つぎのようにopacityプロパティではじめは透明(0)にしておく。そして、スイッチの<label>要素class属性"button")のクリックでオンとオフが切り替わるチェックボックスの<input>要素class属性"check")に、:checked擬似クラスでプロパティを不透明(1)に戻す。ついでに、スイッチにマウスポインタを重ねたとき:hover擬似クラス)は半透明にした。

.button div::after {

    opacity: 0;

}
.button div:hover::after {
    opacity: 0.3;
}

.check:checked ~ .button div::after {
    opacity: 1;
}

チェックボックスの<input>要素class属性"check")がチェックされたら:checked擬似クラス)灯りをつける。電灯の::before擬似要素は、背景色を白く変え、box-shadowプロパティで半透明の白い光彩を重ねた。そして、transitionプロパティでアニメーションさせればよい。これで、スイッチをクリックすれば、電灯がついたり消えたりする。書き上がったCSSの定めは、以下のコード4にまとめた。

.lamp::before {

    transition: 0.15s;
}

.check:checked ~ .lamp::before {
    background: white;
    box-shadow: 0px 2px 10px rgba(255, 255, 255, 0.8),
        0px 5px 50px rgba(255, 255, 255, 0.8),
        0px 8px 80px rgba(255, 255, 255, 0.6),
        0px 8px 120px rgba(255, 255, 255, 0.6);
}
図6 ボタンスイッチで電灯がついたり消えたりする
図6 ボタンスイッチで電灯がついたり消えたりする
コード4 ボタンスイッチで電灯をつけたり消したりするアニメーション
body {
    background: #2f323c;
}
.container {
    position: relative;
    width: 100vw;
    height: 100vh;
}
.lamp {
    position: relative;
    margin: -19px auto;
    width: 0.7rem;
    height: 10rem;
    background-image: linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)),
        linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)),
        linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7));
    background-repeat: no-repeat;
    background-size: 0.15rem 8rem,
        0.4rem 0.8rem,
        0.7rem 2rem;
    background-position: 50% 0,
        0.19rem 8rem,
        0 8.8rem;
}
.lamp::before {
    content: '';
    position: absolute;
    left: -1.65rem;
    bottom: -4rem;
    width: 4rem;
    height: 4rem;
    border-radius: 50%;
    background: rgba(255,255, 255, 0.03);
    box-shadow: inset 2px -2px 10px rgba(255, 255, 255, 0.07);
    transition: 0.15s;
}
.light {
    position: absolute;
    top: 10.05rem;
    left: 0.25rem;
    height: 1.5rem;
    border-right: 0.2rem solid rgba(255, 255, 255, 0.05);
}
.light::before {
    position: absolute;
    box-sizing: border-box;
    content: '';
    top: 1.5rem;
    left: -0.35rem;
    width: 0.9rem;
    height: 0.9rem;
    border-radius: 50%;
    border: 0.2rem solid rgba(255, 255, 255, 0.05);
}
.check:checked ~ .lamp::before {
    background: white;
    box-shadow: 0px 2px 10px rgba(255, 255, 255, 0.8),
        0px 5px 50px rgba(255, 255, 255, 0.8),
        0px 8px 80px rgba(255, 255, 255, 0.6),
        0px 8px 120px rgba(255, 255, 255, 0.6);
}
.button::before {
    content: '';
    width: 28px;
    height: 28px;
    position: absolute;
    left: 0;
    background: linear-gradient(to bottom, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%);
    border-radius: 50%;
    box-shadow: inset 0px 1px 1px white,
        0px 1px 3px rgba(0, 0, 0, 0.5);
}
.button div {
    width: 20px;
    height: 20px;
    cursor: pointer;
    position: absolute;
    left: 4px;
    top: 4px;
    background: linear-gradient(to bottom, #222222 0%, #45484d 100%);
    border-radius: 50%;
}
.button div::after {
    content: '';
    width: 16px;
    height: 16px;
    position: absolute;
    top: 2px;
    left: 2px;
    background: #27ae60;
    background: linear-gradient(to bottom, #27ae60 0%, #145b32 100%);
    opacity: 0;
    border-radius: 50%;
    box-shadow: inset 0px 1px 1px white,
        0px 1px 3px rgba(0, 0, 0, 0.5);
}
.button div:hover::after {
    opacity: 0.3;
}
.check {
    visibility: hidden;
}
.check:checked ~ .button div::after {
    opacity: 1;
}

おすすめ記事

記事・ニュース一覧