CSS / SVG を利用して、スネークタイプのスピナーリングのアニメーションを作成する - CSS

CSS / SVG を利用して、スネークタイプのスピナーリングのアニメーションを作成するコードを紹介します。

概要

Webページなどで時間のかかる処理をする場合、リングのアニメーションを表示して処理が止まっていないことを表示することがあります。この記事では、CSSを利用してリングのアニメーションを表示するコードを紹介します。

参考

今回は、md-preloader(https://github.com/rtheunissen/md-preloader)という、Googleで利用されているスピナーのアニメーションを実装したCSSを利用しています。

コード

下記のHTMLファイル、CSSファイルを作成します。
SinnerRingMd.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
    <link rel="stylesheet" href="SpinnerRingMd.css" />
</head>
<body>
    <div class="md-preloader">
        <svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="160" width="160" viewBox="0 0 75 75">
        <circle cx="37.5" cy="37.5" r="33.5" stroke-width="8" />
        </svg>
    </div>
</body>
</html>
SinnerRingMd.css
.md-preloader {
    font-size: 0;
    display: inline-block;
    -webkit-animation: outer 6600ms linear infinite;
    animation: outer 6600ms linear infinite
}

.md-preloader svg {
    -webkit-animation: inner 1320ms linear infinite;
    animation: inner 1320ms linear infinite
}

.md-preloader svg circle {
    fill: none;
    stroke: #448aff;
    stroke-linecap: square;
    -webkit-animation: arc 1320ms cubic-bezier(.8, 0, .4, .8) infinite;
    animation: arc 1320ms cubic-bezier(.8, 0, .4, .8) infinite
}

@-webkit-keyframes outer {
    0% {
        -webkit-transform: rotate(0);
        transform: rotate(0)
    }

    100% {
        -webkit-transform: rotate(360deg);
        transform: rotate(360deg)
    }
}

@keyframes outer {
    0% {
        -webkit-transform: rotate(0);
        transform: rotate(0)
    }

    100% {
        -webkit-transform: rotate(360deg);
        transform: rotate(360deg)
    }
}

@-webkit-keyframes inner {
    0% {
        -webkit-transform: rotate(-100.8deg);
        transform: rotate(-100.8deg)
    }

    100% {
        -webkit-transform: rotate(0);
        transform: rotate(0)
    }
}

@keyframes inner {
    0% {
        -webkit-transform: rotate(-100.8deg);
        transform: rotate(-100.8deg)
    }

    100% {
        -webkit-transform: rotate(0);
        transform: rotate(0)
    }
}

@-webkit-keyframes arc {
    0% {
        stroke-dasharray: 1 210.48670779px;
        stroke-dashoffset: 0
    }

    40% {
        stroke-dasharray: 151.55042961px,210.48670779px;
        stroke-dashoffset: 0
    }

    100% {
        stroke-dasharray: 1 210.48670779px;
        stroke-dashoffset: -151.55042961px
    }
}

@keyframes arc {
    0% {
        stroke-dasharray: 1 210.48670779px;
        stroke-dashoffset: 0
    }

    40% {
        stroke-dasharray: 151.55042961px,210.48670779px;
        stroke-dashoffset: 0
    }

    100% {
        stroke-dasharray: 1 210.48670779px;
        stroke-dashoffset: -151.55042961px
    }
}

実行結果

最初に動作結果を確認します。上記のHTMLファイルを開くとスピナーリングが表示されアニメーションします。アニメーションはリングが伸縮する複雑な動きをしているように見えます。



解説

最初にすべてのアニメーションを停止するとどのような表示になる確認します。CSSの下記をコメントアウトします。
.md-preloader {
    font-size: 0;
    display: inline-block;
    /*
    -webkit-animation: outer 6600ms linear infinite;
    animation: outer 6600ms linear infinite
    */
}

.md-preloader svg {
    /*
    -webkit-animation: inner 1320ms linear infinite;
    animation: inner 1320ms linear infinite
    */
}

.md-preloader svg circle {
    fill: none;
    stroke: #448aff;
    stroke-linecap: square;
    /*
    -webkit-animation: arc 1320ms cubic-bezier(.8, 0, .4, .8) infinite;
    animation: arc 1320ms cubic-bezier(.8, 0, .4, .8) infinite
    */
}

実行すると、下図の画面が表示されます。アニメーションしないリングが表示されます。


続いて、md-preloader svg circle のアニメーションを有効にします。
.md-preloader svg circle {
    fill: none;
    stroke: #448aff;
    stroke-linecap: square;
    -webkit-animation: arc 1320ms cubic-bezier(.8, 0, .4, .8) infinite;
    animation: arc 1320ms cubic-bezier(.8, 0, .4, .8) infinite
}

上記を実行すると、下図のアニメーションが表示されます。円の3時部分から線が伸び、12時部分まで線が伸び、その後3時部分が縮み始め、リンクが縮むアニメーションが繰り返されます。





アニメーションのキーフレーム部分のarcを確認します。stroke-dasharrayを変化させており、アニメーションは点線の空白部分の長さをアニメーションすることで、円の線が伸びているように見せていることがわかります。40%の位置まで点線の空白部分を縮め、40%から100%までは点線の空白部分を伸ばしつつオフセットを減らすアニメーションになります。40%がキーフレームになっているのは、素早く伸びて、縮むスピードは伸びる速度より若干遅くするためのものです。
@keyframes arc {
    0% {
        stroke-dasharray: 1 210.48670779px;
        stroke-dashoffset: 0
    }

    40% {
        stroke-dasharray: 151.55042961px,210.48670779px;
        stroke-dashoffset: 0
    }

    100% {
        stroke-dasharray: 1 210.48670779px;
        stroke-dashoffset: -151.55042961px
    }
}

続いて、md-preloader svg クラスのアニメーションのみを有効にします。動作をわかりやすくするため、border: 1px solid #ff6a00; を追加しています。
.md-preloader {
    font-size: 0;
    display: inline-block;
    /*
    -webkit-animation: outer 6600ms linear infinite;
    animation: outer 6600ms linear infinite
    */
}

.md-preloader svg {
    border: 1px solid #ff6a00;
    -webkit-animation: inner 1320ms linear infinite;
    animation: inner 1320ms linear infinite
}

.md-preloader svg circle {
    fill: none;
    stroke: #448aff;
    stroke-linecap: square;
    /*
    -webkit-animation: arc 1320ms cubic-bezier(.8, 0, .4, .8) infinite;
    animation: arc 1320ms cubic-bezier(.8, 0, .4, .8) infinite
    */
}

上記のCSSでHTMLファイルを表示するとリングの周囲にオレンジの枠が表示されます。


オレンジの枠がリングの中心を中心にして回転することが確認できます。



続いて、md-preloader クラスのアニメーションも有効にします。こちらも動作がわかりやすくなるよう、border: 1px solid #ff0000; を追記します。
.md-preloader {
    border: 1px solid #ff0000;
    font-size: 0;
    display: inline-block;
    -webkit-animation: outer 6600ms linear infinite;
    animation: outer 6600ms linear infinite
}

.md-preloader svg {
    border: 1px solid #ff6a00;
    -webkit-animation: inner 1320ms linear infinite;
    animation: inner 1320ms linear infinite
}

.md-preloader svg circle {
    fill: none;
    stroke: #448aff;
    stroke-linecap: square;
    /*
    -webkit-animation: arc 1320ms cubic-bezier(.8, 0, .4, .8) infinite;
    animation: arc 1320ms cubic-bezier(.8, 0, .4, .8) infinite
    */
}

上記のCSSでHTMLファイルを表示すると、オレンジと赤色の枠がリングの周囲に表示されます。2つの枠の回転速度が違ってアニメーションすることが確認できます。




補足:外側の枠が回転しないとどうなるのか?

今回のアニメーションでは外側の枠と内側の枠が異なる速度で回転しています。もし、外側の枠が回転しないとどのような動作になるか確認します。下記のようにCSSを変更し外側の枠の回転を止めます。
.md-preloader {
    border: 1px solid #ff0000;
    font-size: 0;
    display: inline-block;
    /*
    -webkit-animation: outer 6600ms linear infinite;
    animation: outer 6600ms linear infinite
    */
}

.md-preloader svg {
    border: 1px solid #ff6a00;
    -webkit-animation: inner 1320ms linear infinite;
    animation: inner 1320ms linear infinite
}

HTMLファイルを表示します。リングが12時のところから伸び始めます。


枠が回転するため2時の位置まで移動したときに10時の位置までリングが伸びます。


リングが縮み始め、リングの終端が12時の位置に来るとリングが縮みます。


このアニメーションが繰り返されるため、リングの開始がいつも12時から伸び始めるため、アニメーションに変化がつかなくなってしまいます。そのためさらに全体をゆっくり回転させて、リングの開始が12時からにならないような変化をつけています。

著者
iPentecのメインデザイナー
Webページ、Webクリエイティブのデザインを担当。PhotoshopやIllustratorの作業もする。
掲載日: 2019-08-29
iPentec all rights reserverd.