CSSだけでボールが回転する3種類のloadingを作る方法

Loadingアイコンメーカーはじめました(2015年9月3日)
15/6/11追記)Safariで正しく動作しないことが判明しましたので、作成をし直しました。こちらをご覧ください

以前、CSSだけで矢印が回転するloadingを作る方法を紹介しましたが、今度はもっともメジャーなloadingの1つであるボールが回転する下記のようなタイプを、CSSだけで作成します。

HTMLは中にspanを2つ入れて、
<span class="loading"><span></span><span></span></span>
です。
上記の例のうち、左のパターンのCSSは次のようになります。

span.loading_blog {
    position: relative;
    display: inline-block;
    width: 50px; /*diameter*/
    height: 50px;
    margin: 0 10px;
}

span.loading_blog:before, span.loading_blog:after,
span.loading_blog > span:first-child, span.loading_blog > span:first-child:before, span.loading_blog > span:first-child:after,
span.loading_blog > span:last-child, span.loading_blog > span:last-child:before, span.loading_blog > span:last-child:after {
    position: absolute;
    display: inline-block;
    content: " ";
    width: 6px; /*width*/
    height: 6px;
    border-radius: 3px 3px; /*{width/2}px {width/2}px*/
    background-color: #000;
    -moz-animation: rotating 0.8s linear infinite;
    -webkit-animation: rotating 0.8s linear infinite;
    -o-animation: rotating 0.8s linear infinite;
    -ms-animation: rotating 0.8s linear infinite;
}
    span.loading_blog:before {
        left: 50%;
        top: 0;
        margin-left: -3px; /*{width/2}px*/

    }
    span.loading_blog:after {
        left: 50%;
        bottom: 0;
        margin-left: -3px; /*{width/2}px*/
        -moz-animation-delay: 0.4s;
        -webkit--animation-delay: 0.4s;
        -o-animation-delay: 0.4s;
        -ms-animation-delay: 0.4s;
    }

    span.loading_blog > span:first-child {
        left: 0;
        top: 50%;
        margin-top: -3px; /*{width/2}px*/
        -moz-animation-delay: 0.6s;
        -webkit--animation-delay: 0.6s;
        -o-animation-delay: 0.6s;
        -ms-animation-delay: 0.6s;
    }
    span.loading_blog > span:first-child:before {
        left: 7.3px; /*1 {diameter*0.146}px = {(diameter/2)*(1-1/sqrt(2))}px*/
        top: 14.7px; /*2 {(diameter*0.354-width/2}px = {(diameter/2)*(1/sqrt(2))-width/2}px*/
        -moz-animation-delay: 0.5s;
        -webkit--animation-delay: 0.5s;
        -o-animation-delay: 0.5s;
        -ms-animation-delay: 0.5s;
    }
    span.loading_blog > span:first-child:after {
        left: 7.3px; /*1*/
        bottom: 14.7px; /*2*/
        -moz-animation-delay: 0.7s;
        -webkit--animation-delay: 0.7s;
        -o-animation-delay: 0.7s;
        -ms-animation-delay: 0.7s;
    }

    span.loading_blog > span:last-child {
        right: 0;
        top: 50%;
        margin-top: -3px; /*{width/2}px*/
        -moz-animation-delay: 0.2s;
        -webkit--animation-delay: 0.2s;
        -o-animation-delay: 0.2s;
        -ms-animation-delay: 0.2s;
    }
    span.loading_blog > span:last-child:before {
        right: 7.3px; /*1*/
        top: 14.7px; /*2*/
        -moz-animation-delay: 0.3s;
        -webkit--animation-delay: 0.3s;
        -o-animation-delay: 0.3s;
        -ms-animation-delay: 0.3s;
    }
    span.loading_blog > span:last-child:after {
        right: 7.3px; /*1*/
        bottom: 14.7px; /*2*/
        -moz-animation-delay: 0.1s;
        -webkit--animation-delay: 0.1s;
        -o-animation-delay: 0.1s;
        -ms-animation-delay: 0.1s;
    }

    @-moz-keyframes rotating {
        0% {
            background-color: #fff;
        }
        100% {
            background-color: #000;
        }
    }
    @-webkit-keyframes rotating {
        0% {
            background-color: #fff;
        }
        100% {
            background-color: #000;
        }
    }
    @-o-keyframes rotating {
        0% {
            background-color: #fff;
        }
        100% {
            background-color: #000;
        }
    }
    @-ms-keyframes rotating {
        0% {
            background-color: #fff;
        }
        100% {
            background-color: #000;
        }
    }

疑似要素:beforeと:afterを利用することで、1つのspanで3つのボールが表示できます。これにより3つのspanで8つのボールを表現しています。ただし、外側のspan自身は外周として利用しています。
{prefix}-animationとkeyframesの部分でアニメーションを定義しています。
アニメーションは非常にシンプルで、色を背景色#ffffからボールの色#000に変化してさせるだけです。
各ボールにanimation-delayを定義し、これを0.1秒ごとに実行させることで回転を疑似表現しています。

大きさや色の調整

50pxとしているloading全体の直径をdiameter、6pxとしているボールの直径をwidthという変数に見立て、/*コメントアウト*/内にdiameter・widthを変更した際の計算方法を記入しました。これにより、全体のサイズ、ボールのサイズが変更できます。
色は、#000をボールの色、#fffを背景色として変更できます。

アニメーションのバリエーション1

左の例は、CSSのkeyframesの中身を下記のように書き換え、変化の対象をbackground-colorからbox-shadowに換えます。

        0% {
            box-shadow: rgba(0, 0, 0, 1) 0 0 2px;
            -webkit-box-shadow: rgba(0, 0, 0, 1) 0 0 2px;
            -moz-box-shadow: rgba(0, 0, 0, 1) 0 0 2px;
        }
        100% {
            box-shadow: none;
            -webkit-box-shadow: none;
            -moz-box-shadow: none;
        }

アニメーションのバリエーション2

左の例は、CSSを下記のように書き換え、アニメーションの対象をボールから外周に換えます。keyframesはtransform: rotateで回転をさせています。
また、animation-delayの定義は不要なので全て削除できます。

span.loading {
    position: relative;
    display: inline-block;
    width: 50px; /*diameter*/
    height: 50px;
    margin: 0 10px;

    -moz-animation: rotating 3s linear infinite;
    -webkit-animation: rotating 3s linear infinite;
    -o-animation: rotating 3s linear infinite;
    -ms-animation: rotating 3s linear infinite;
}

span.loading:before, span.loading:after,
span.loading > span:first-child, span.loading > span:first-child:before, span.loading > span:first-child:after,
span.loading > span:last-child, span.loading > span:last-child:before, span.loading > span:last-child:after {
    position: absolute;
    display: inline-block;
    content: " ";
    width: 6px; /*width*/
    height: 6px;
    border-radius: 3px 3px; /*{width/2}px {width/2}px*/
    background-color: #000;
}

    span.loading_blog:before {
        left: 50%;
        top: 0;
        margin-left: -3px; /*{width/2}px*/

    }
    span.loading_blog:after {
        left: 50%;
        bottom: 0;
        margin-left: -3px; /*{width/2}px*/
    }

    span.loading_blog > span:first-child {
        left: 0;
        top: 50%;
        margin-top: -3px; /*{width/2}px*/
    }
    span.loading_blog > span:first-child:before {
        left: 7.3px; /*1 {diameter*0.146}px = {(diameter/2)*(1-1/sqrt(2))}px*/
        top: 14.7px; /*2 {(diameter*0.354-width/2}px = {(diameter/2)*(1/sqrt(2))-width/2}px*/
    }
    span.loading_blog > span:first-child:after {
        left: 7.3px; /*1*/
        bottom: 14.7px; /*2*/
    }

    span.loading_blog > span:last-child {
        right: 0;
        top: 50%;
        margin-top: -3px; /*{width/2}px*/
    }
    span.loading_blog > span:last-child:before {
        right: 7.3px; /*1*/
        top: 14.7px; /*2*/
    }
    span.loading_blog > span:last-child:after {
        right: 7.3px; /*1*/
        bottom: 14.7px; /*2*/
    }

    @-moz-keyframes rotating {
        0% {
            -moz-transform: rotate(0deg);
        }
        100% {
            -moz-transform: rotate(360deg);
        }
    }
    @-webkit-keyframes rotating {
        0% {
            -webkit-transform: rotate(0deg);
        }
        100% {
            -webkit-transform: rotate(360deg);
        }
    }
    @-o-keyframes rotating {
        0% {
            -o-transform: rotate(0deg);
        }
        100% {
            -o-transform: rotate(360deg);
        }
    }
    @-ms-keyframes rotating {
        0% {
            -ms-transform: rotate(0deg);
        }
        100% {
            -ms-transform: rotate(360deg);
        }
    }

クロスブラウザ対策

以上はモダンブラウザおよびIE10以上で利用できますが、IE9以下の対策に下記を追記します。
IE8・IE9では「loading」の文字が表示されます。

<!--[if lte IE 9 ]>
<style type="text/css">
    /*ボールを隠す*/
    span.loading:before, span.loading > span {
        display: none !important;
    }

    /*loadingメッセージを表示*/
    span.loading:after {
        content: "loading";
        left: 0;
        right: 0;
        top: 50%;
        width: auto;
        height: auto;
        margin-left: 0;
        background-color: transparent;
        text-align: center;
        line-height: 0;
    }
</style>
<![endif]-->

例えば14pxの小さなサイズでも使えるのが便利

このように外周の直径を14px、ボールを1pxにしても利用できるので、小さなスペースにも活用出来て便利です。
CSSだけなので、もちろんどんな背景にも合わせることができます。

2015/5/21