ローディングサンプル1の作り方
ローディングサンプル1は、円周上をグルグル回るタイプのローディングアニメーションですが、サンプル2と比べると実装が簡単なのでこちらから紹介していきます。
まず正方形の要素を用意し、borderで境界線を設定→border-radiusで四隅を丸めて正円にします。
box-sizingは、全ての要素でborder-boxであるものとします
<div class="loading_circle"></div>
.loading_circle {
width: 200px;
height: 200px;
border-radius: 50%;
border: solid 15px rgb(201, 228, 255);
}
この円は背景の役割を果たすので、境界線の色は薄めの色の方がオススメです。
なお、今回は表示結果を見やすくするため大きめのサイズ(200px)で作成していますが、実際はもっと小さくて良い場合が多いかと思います。
円ができたら今度は擬似要素を使って、同じ大きさで円を重ねていきます。
この際、親要素の役割を果たすdiv要素(loading_circle)に、positionプロパティを指定して基準位置としておくのも忘れないようにしましょう。
.loading_circle {
width: 200px;
height: 200px;
border-radius: 50%;
border: solid 15px rgb(201, 228, 255);
position: relative;
}
.loading_circle::before {
content: "";
position: absolute;
width: 100%;
height: 100%;
top: -15px;
left: -15px;
border-radius: 50%;
border: solid 15px rgb(41, 124, 207);
}
擬似要素の円を同じ大きさ、同じ境界線の太さで重ねているので、div要素(loading_circle)は隠れて見えない状態になっています。
なお、円を重ねる位置を調整する際、境界線の太さの分だけtopとleftプロパティで移動させてピッタリ重なるようにしましょう。
このままでは円を回転させても意味がないので、clip-pathを使って必要な部分だけクリッピングしていきます。
.loading_circle {
width: 200px;
height: 200px;
border-radius: 50%;
border: solid 15px rgb(201, 228, 255);
position: relative;
}
.loading_circle::before {
content: "";
position: absolute;
width: 100%;
height: 100%;
top: -15px;
left: -15px;
border-radius: 50%;
border: solid 15px rgb(41, 124, 207);
clip-path: polygon(25% 0%, 75% 0%, 50% 50%);
}
clip-pathでは、下の図の濃いグレーの部分をクリッピング(切り抜き)しています。
clip-pathで切り抜かれる範囲
あとは、この擬似要素をanimationプロパティを使ってグルグル回転させれば完成です!
ここではシンプルに、一回転を連続で繰り返すアニメーションを指定してみたいと思います。
.loading_circle {
width: 200px;
height: 200px;
border-radius: 50%;
border: solid 15px rgb(201, 228, 255);
position: relative;
}
.loading_circle::before {
content: "";
position: absolute;
width: 100%;
height: 100%;
top: -15px;
left: -15px;
border-radius: 50%;
border: solid 15px rgb(41, 124, 207);
clip-path: polygon(25% 0%, 75% 0%, 50% 50%);
animation: loading_circle 1s linear infinite;
}
@keyframes loading_circle {
to {
transform: rotate(360deg);
}
}
円の円周上をグルグル回るローディングアニメーションができました!
animationプロパティのlinear(リニア)の指定は、アニメーションの速度を均一にするもので、アニメーションに緩急をつけたくない場合などに使用されます。
1sの部分はアニメーションの開始〜終了までの秒数、infiniteはアニメーションを無限に繰り返す設定になります。
POINT!
- ・正円を2つ用意して、ピッタリ重ね合わせよう!
- ・上に重ねた円を、clip-pathで必要な部分だけ切り取ろう!
- ・上に重ねた円を、animationで回転するアニメーションを指定すれば完成!
ローディングサンプル2の作り方(準備編)
次は、カプセル状の図形が放射状に並び、グレーの濃さが移り変わることによってグルグル回転しているように見えるローディングアニメーションを作ってみましょう。
まずは準備段階として、各パーツのスタイルと位置を調整することを目標にします。
縦長のカプセル状の要素と、同じ幅の円形の要素をそれぞれ用意し、marginで距離を離して配置した上で、コンテナとなる親要素の幅と高さが子要素にフィットするように、fit-contentを指定します。
<div class="loading_item_container item1">
<div class="loading_item"></div>
<div class="transform_origin"></div>
</div>
.loading_item_container {
width: fit-content;
height: fit-content;
}
.loading_item {
width: 20px;
height: 50px;
background-color: rgb(65, 65, 65);
border-radius: 10px;
}
.transform_origin {
width: 20px;
height: 20px;
margin-top: 30px;
border-radius: 50%;
background-color: pink;
}
ピンク色の円形のdiv要素には”transform_origin”というclass名をつけていることから予想できると思いますが、この要素は、transformで回転させる際の基準点を分かりやすくするための要素です。
要素を増やしてposition(absolute)で重ね、ピンクの円の中心を基準にして要素を回転させることで、カプセル状の要素がキレイに放射状に並びます。
次のステップでは、最初のステップで作った要素を合計8個に増やして、全体の親要素となる要素を用意→positionの基準点として8個の要素を重ねます。
そして、transform-originでピンクの円の中心が変形の基準点になるように指定し、各要素を一定の角度で回転させてローディングアニメーションの形を作ります。
<div class="loading_outer">
<div class="loading_item_container item1">
<div class="loading_item"></div>
<div class= "transform_origin"></div>
</div>
<div class="loading_item_container item2">
<div class="loading_item"></div>
<div class= "transform_origin"></div>
</div>
<div class="loading_item_container item3">
<div class="loading_item"></div>
<div class= "transform_origin"></div>
</div>
<div class="loading_item_container item4">
<div class="loading_item"></div>
<div class= "transform_origin"></div>
</div>
<div class="loading_item_container item5">
<div class="loading_item"></div>
<div class= "transform_origin"></div>
</div>
<div class="loading_item_container item6">
<div class="loading_item"></div>
<div class= "transform_origin"></div>
</div>
<div class="loading_item_container item7">
<div class="loading_item"></div>
<div class= "transform_origin"></div>
</div>
<div class="loading_item_container item8">
<div class="loading_item"></div>
<div class= "transform_origin"></div>
</div>
</div>
.loading_outer {
width: 180px;
height: 180px;
position: relative;
}
.loading_item_container {
width: fit-content;
height: fit-content;
position: absolute;
left: 0;
right: 0;
margin: auto;
transform-origin: 10px 90px;
}
.loading_item {
width: 20px;
height: 50px;
background-color: rgb(65, 65, 65);
border-radius: 10px;
}
.transform_origin {
width: 20px;
height: 20px;
margin-top: 30px;
border-radius: 50%;
background-color: pink;
}
.item1 {
transform: rotate(0deg);
}
.item2 {
transform: rotate(45deg);
}
.item3 {
transform: rotate(90deg);
}
.item4 {
transform: rotate(135deg);
}
.item5 {
transform: rotate(180deg);
}
.item6 {
transform: rotate(225deg);
}
.item7 {
transform: rotate(270deg);
}
.item8 {
transform: rotate(315deg);
}
カプセル状の要素(loading_item)を放射状にキレイに並べることができました!
なお、transform-originの値が 10px 90px となるのがイメージしづらいという方は、下の図も参考にしてみてください。
ピンクの円の中心がtransform-origin
あとはanimationプロパティで各要素のグレーの濃淡(不透明度)を変えていくことで、ローディングアニメーション2の完成となります!
なお、中心のピンクの円はこの時点で不要となるので、opacityプロパティなどで見えなくしておきましょう。
POINT!
- ・要素を放射状にキレイに並べたい場合は、transform-originを活用しよう!
- ・今回の例では、ピンクの円形の要素の中心をtransform-originで変形の基準点にしている!
- ・混乱してしまったら、図を描いて整理するとわかりやすい!
ローディングサンプル2の作り方(アニメーション編)
前のステップでカプセル状の要素を放射状に並べることができたので、次は各要素にアニメーションを指定していきます。
ですがその前に、まずは各要素にopacityで濃淡をつけておきましょう。
.loading_outer {
width: 180px;
height: 180px;
position: relative;
}
.loading_item_container {
width: fit-content;
height: fit-content;
position: absolute;
left: 0;
right: 0;
margin: auto;
transform-origin: 10px 90px;
}
.loading_item {
width: 20px;
height: 50px;
background-color: rgb(65, 65, 65);
border-radius: 10px;
}
.transform_origin {
width: 20px;
height: 20px;
margin-top: 30px;
border-radius: 50%;
background-color: pink;
opacity: 0;
}
.item1 {
transform: rotate(0deg);
opacity: .8;
}
.item2 {
transform: rotate(45deg);
opacity: .1;
}
.item3 {
transform: rotate(90deg);
opacity: .2;
}
.item4 {
transform: rotate(135deg);
opacity: .3;
}
.item5 {
transform: rotate(180deg);
opacity: .4;
}
.item6 {
transform: rotate(225deg);
opacity: .5;
}
.item7 {
transform: rotate(270deg);
opacity: .6;
}
.item8 {
transform: rotate(315deg);
opacity: .7;
}
だいぶそれっぽくなってきましたね!
あとはanimationプロパティを用いて、アニメーションを指定すれば完成です。
全部で8個の要素があり、不透明度の段階は8段階必要となるので、100% / 8 = 12.5% に区切ってアニメーションを設定していきます。
アニメーション自体は、opacityの値を変化させるだけのシンプルなものです。
以上を踏まえて、最終的なCSSコードを確認していきましょう!
.loading_outer {
width: 180px;
height: 180px;
position: relative;
}
.loading_item_container {
width: fit-content;
height: fit-content;
position: absolute;
left: 0;
right: 0;
margin: auto;
transform-origin: 10px 90px;
}
.loading_item {
width: 20px;
height: 50px;
background-color: rgb(65, 65, 65);
border-radius: 10px;
}
.transform_origin {
width: 20px;
height: 20px;
margin-top: 30px;
border-radius: 50%;
background-color: pink;
opacity: 0;
}
.item1 {
transform: rotate(0deg);
opacity: .8;
animation: loading1 .8s linear infinite;
}
.item2 {
transform: rotate(45deg);
opacity: .1;
animation: loading2 .8s linear infinite;
}
.item3 {
transform: rotate(90deg);
opacity: .2;
animation: loading3 .8s linear infinite;
}
.item4 {
transform: rotate(135deg);
opacity: .3;
animation: loading4 .8s linear infinite;
}
.item5 {
transform: rotate(180deg);
opacity: .4;
animation: loading5 .8s linear infinite;
}
.item6 {
transform: rotate(225deg);
opacity: .5;
animation: loading6 .8s linear infinite;
}
.item7 {
transform: rotate(270deg);
opacity: .6;
animation: loading7 .8s linear infinite;
}
.item8 {
transform: rotate(315deg);
opacity: .7;
animation: loading8 .8s linear infinite;
}
@keyframes loading1 {
0% { opacity: .8; }
12.5% { opacity: .7; }
25% { opacity: .6; }
37.5% { opacity: .5; }
50% { opacity: .4; }
62.5% { opacity: .3; }
75% { opacity: .2; }
87.5% { opacity: .1; }
}
@keyframes loading2 {
0% { opacity: .1; }
12.5% { opacity: .8; }
25% { opacity: .7; }
37.5% { opacity: .6; }
50% { opacity: .5; }
62.5% { opacity: .4; }
75% { opacity: .3; }
87.5% { opacity: .2; }
}
@keyframes loading3 {
0% { opacity: .2; }
12.5% { opacity: .1; }
25% { opacity: .8; }
37.5% { opacity: .7; }
50% { opacity: .6; }
62.5% { opacity: .5; }
75% { opacity: .4; }
87.5% { opacity: .3; }
}
@keyframes loading4 {
0% { opacity: .3; }
12.5% { opacity: .2; }
25% { opacity: .1; }
37.5% { opacity: .8; }
50% { opacity: .7; }
62.5% { opacity: .6; }
75% { opacity: .5; }
87.5% { opacity: .4; }
}
@keyframes loading5 {
0% { opacity: .4; }
12.5% { opacity: .3; }
25% { opacity: .2; }
37.5% { opacity: .1; }
50% { opacity: .8; }
62.5% { opacity: .7; }
75% { opacity: .6; }
87.5% { opacity: .5; }
}
@keyframes loading6 {
0% { opacity: .5; }
12.5% { opacity: .4; }
25% { opacity: .3; }
37.5% { opacity: .2; }
50% { opacity: .1; }
62.5% { opacity: .8; }
75% { opacity: .7; }
87.5% { opacity: .6; }
}
@keyframes loading7 {
0% { opacity: .6; }
12.5% { opacity: .5; }
25% { opacity: .4; }
37.5% { opacity: .3; }
50% { opacity: .2; }
62.5% { opacity: .1; }
75% { opacity: .8; }
87.5% { opacity: .7; }
}
@keyframes loading8 {
0% { opacity: .7; }
12.5% { opacity: .6; }
25% { opacity: .5; }
37.5% { opacity: .4; }
50% { opacity: .3; }
62.5% { opacity: .2; }
75% { opacity: .1; }
87.5% { opacity: .8; }
}
要素の数が多いのでアニメーションの指定がちょっと大変ですが、これにて無事に完成です!
ローディングアニメーションをGIFや動画ファイルではなく、CSSアニメーションで実装するメリットとしては、色やアニメーションのスピードなどを柔軟に変更できるという点が大きいです。
たとえば季節やイベントに合わせてローディングアニメーションのカラーを変えるなど、臨機応変にスタイルを変更したい場合は、CSSで準備しておいた方が便利かなと思います。
POINT!
- ・opacityで不透明度に差をつけて、要素に濃淡を持たせよう!
- ・各要素のopacityをアニメーションで変化させて、ローディングを表現しよう!
- ・CSSで実装しておくと、後でカラーやスピードを変更するのも楽になる!
ローディングサンプル3の作り方
ローディングサンプル3は、ローディングサンプル2の形状とアニメーションをほんの少し変更するだけで作れます。
ローディングサンプル2は要素の形をカプセル状にしていましたが、ローディングサンプル3では、widthとheightを同じ値にして角を最大に丸めて円形にします。
そして、円形にした要素に対して transform: scale() を加えたアニメーションを指定すれば、それで完成です。
ここまで記事を読み進めて下さった方なら、コードをパッと確認するだけで理解できると思うので、いきなりですが完成系のコードを掲載します!
<div class="loading_outer">
<div class="loading_item_container item1">
<div class="loading_item circle1"></div>
<div class= "transform_origin"></div>
</div>
<div class="loading_item_container item2">
<div class="loading_item circle2"></div>
<div class= "transform_origin"></div>
</div>
<div class="loading_item_container item3">
<div class="loading_item circle3"></div>
<div class= "transform_origin"></div>
</div>
<div class="loading_item_container item4">
<div class="loading_item circle4"></div>
<div class= "transform_origin"></div>
</div>
<div class="loading_item_container item5">
<div class="loading_item circle5"></div>
<div class= "transform_origin"></div>
</div>
<div class="loading_item_container item6">
<div class="loading_item circle6"></div>
<div class= "transform_origin"></div>
</div>
<div class="loading_item_container item7">
<div class="loading_item circle7"></div>
<div class= "transform_origin"></div>
</div>
<div class="loading_item_container item8">
<div class="loading_item circle8"></div>
<div class= "transform_origin"></div>
</div>
</div>
.loading_outer {
width: 180px;
height: 180px;
position: relative;
}
.loading_item_container {
width: fit-content;
height: fit-content;
position: absolute;
left: 0;
right: 0;
margin: auto;
transform-origin: 10px 90px;
}
.loading_item {
width: 20px;
height: 20px;
background-color: rgb(65, 65, 65);
border-radius: 50%;
}
.transform_origin {
width: 20px;
height: 20px;
margin-top: 30px;
border-radius: 50%;
background-color: pink;
opacity: 0;
}
.item1 {
transform: rotate(0deg);
}
.item2 {
transform: rotate(45deg);
}
.item3 {
transform: rotate(90deg);
}
.item4 {
transform: rotate(135deg);
}
.item5 {
transform: rotate(180deg);
}
.item6 {
transform: rotate(225deg);
}
.item7 {
transform: rotate(270deg);
}
.item8 {
transform: rotate(315deg);
}
.circle1 {
opacity: .8;
transform: scale(1.8);
animation: loading1 .8s linear infinite;
}
.circle2 {
opacity: .1;
transform: scale(1);
animation: loading2 .8s linear infinite;
}
.circle3 {
opacity: .2;
transform: scale(1.2);
animation: loading3 .8s linear infinite;
}
.circle4 {
opacity: .3;
transform: scale(1.3);
animation: loading4 .8s linear infinite;
}
.circle5 {
opacity: .4;
transform: scale(1.4);
animation: loading5 .8s linear infinite;
}
.circle6 {
opacity: .5;
transform: scale(1.5);
animation: loading6 .8s linear infinite;
}
.circle7 {
opacity: .6;
transform: scale(1.6);
animation: loading7 .8s linear infinite;
}
.circle8 {
opacity: .7;
transform: scale(1.7);
animation: loading8 .8s linear infinite;
}
@keyframes loading1 {
0% { opacity: .8; transform: scale(1.8); }
12.5% { opacity: .7; transform: scale(1.7); }
25% { opacity: .6; transform: scale(1.6); }
37.5% { opacity: .5; transform: scale(1.5); }
50% { opacity: .4; transform: scale(1.4); }
62.5% { opacity: .3; transform: scale(1.3); }
75% { opacity: .2; transform: scale(1.2); }
87.5% { opacity: .1; transform: scale(1); }
}
@keyframes loading2 {
0% { opacity: .1; transform: scale(1); }
12.5% { opacity: .8; transform: scale(1.8); }
25% { opacity: .7; transform: scale(1.7); }
37.5% { opacity: .6; transform: scale(1.6); }
50% { opacity: .5; transform: scale(1.5); }
62.5% { opacity: .4; transform: scale(1.4); }
75% { opacity: .3; transform: scale(1.3); }
87.5% { opacity: .2; transform: scale(1.2); }
}
@keyframes loading3 {
0% { opacity: .2; transform: scale(1.2); }
12.5% { opacity: .1; transform: scale(1); }
25% { opacity: .8; transform: scale(1.8); }
37.5% { opacity: .7; transform: scale(1.7); }
50% { opacity: .6; transform: scale(1.6); }
62.5% { opacity: .5; transform: scale(1.5); }
75% { opacity: .4; transform: scale(1.4); }
87.5% { opacity: .3; transform: scale(1.3); }
}
@keyframes loading4 {
0% { opacity: .3; transform: scale(1.3); }
12.5% { opacity: .2; transform: scale(1.2); }
25% { opacity: .1; transform: scale(1); }
37.5% { opacity: .8; transform: scale(1.8); }
50% { opacity: .7; transform: scale(1.7); }
62.5% { opacity: .6; transform: scale(1.6); }
75% { opacity: .5; transform: scale(1.5); }
87.5% { opacity: .4; transform: scale(1.4); }
}
@keyframes loading5 {
0% { opacity: .4; transform: scale(1.4); }
12.5% { opacity: .3; transform: scale(1.3); }
25% { opacity: .2; transform: scale(1.2); }
37.5% { opacity: .1; transform: scale(1); }
50% { opacity: .8; transform: scale(1.8); }
62.5% { opacity: .7; transform: scale(1.7); }
75% { opacity: .6; transform: scale(1.6); }
87.5% { opacity: .5; transform: scale(1.5); }
}
@keyframes loading6 {
0% { opacity: .5; transform: scale(1.5); }
12.5% { opacity: .4; transform: scale(1.4); }
25% { opacity: .3; transform: scale(1.3); }
37.5% { opacity: .2; transform: scale(1.2); }
50% { opacity: .1; transform: scale(1); }
62.5% { opacity: .8; transform: scale(1.8); }
75% { opacity: .7; transform: scale(1.7); }
87.5% { opacity: .6; transform: scale(1.6); }
}
@keyframes loading7 {
0% { opacity: .6; transform: scale(1.6); }
12.5% { opacity: .5; transform: scale(1.5); }
25% { opacity: .4; transform: scale(1.4); }
37.5% { opacity: .3; transform: scale(1.3); }
50% { opacity: .2; transform: scale(1.2); }
62.5% { opacity: .1; transform: scale(1); }
75% { opacity: .8; transform: scale(1.8); }
87.5% { opacity: .7; transform: scale(1.7); }
}
@keyframes loading8 {
0% { opacity: .7; transform: scale(1.7); }
12.5% { opacity: .6; transform: scale(1.6); }
25% { opacity: .5; transform: scale(1.5); }
37.5% { opacity: .4; transform: scale(1.4); }
50% { opacity: .3; transform: scale(1.3); }
62.5% { opacity: .2; transform: scale(1.2); }
75% { opacity: .1; transform: scale(1); }
87.5% { opacity: .8; transform: scale(1.8); }
}
コード量が多く感じるかもしれませんが、複雑なアニメーションではないですし、コピペでパパッとできる部分も多いので、コードの分量ほど手間はかかりません。
それに、こういうのは一度作っておくと後で使い回しができるので、自分のオリジナルを一個用意しておくと何かと便利です。
一方、素材サイトなどからコピペできるものは利用規約を確認しないといけないですし、どんな場面でも自由に使えるわけではなかったりすることもあるので注意が必要です。
POINT!
- ・要素の幅と高さを同じにして、角を最大に丸めて正円の形にしよう!
- ・transformのscale()を加えて、大きさを変えるアニメーションを加えよう!
- ・一度自分のオリジナルを作っておくと、自由に色々なところで使い回せるので便利!