CSSアニメーションとtransform-origin
はじめに
CSSアニメーション以外でのtransform-origin
の使い方ありますか?
transform-origin
と戯れたので今回はこのローディングアニメーションの解説を行います。
完成品
ソースコード
<!DOCTYPE html>
<html lang="ja">
<head>
<meta name="robots" content="noindex">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ee</title>
<style>
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #333;
display: grid;
height: 100vh;
margin: 0;
place-items: center center;
}
.loading {
width: 350px;
height: 50px;
display: flex;
animation: hue-rotate linear 4s 0s infinite;
}
@keyframes hue-rotate {
100% {filter: hue-rotate(360deg);}
}
.loading div {
width: 250px;
height: 50px;
position: relative;
}
.loading div::before,
.loading div::after {
content: "";
display: block;
width: 50px;
height: 50px;
background: rgba(0, 231, 255, 1);
border-radius: 50%;
position: absolute;
box-shadow:
0 0 5px rgba(0, 231, 255, 1),
0 0 10px rgba(0, 231, 255, 1),
0 0 20px rgba(0, 231, 255, 1),
0 0 40px rgba(0, 231, 255, 1),
0 0 80px rgba(0, 231, 255, .5),
0 0 160px rgba(0, 231, 255, .2);
}
.loading div::after {right: 0;}
.loading div:nth-child(1) {animation: rotate1 ease-in-out 2s 0s infinite;}
@keyframes rotate1 {
0%,50% {transform-origin: 50% 50%;}
25% {transform: rotate(180deg);}
26%,50% {transform: rotate(180deg);}
50.1%,100% {transform-origin: 175px 50%;}
100% {transform: rotate(540deg);}
}
.loading div:nth-child(2) {
margin-left: -150px;
animation: rotate2 ease-in-out 2s 0s infinite;
}
@keyframes rotate2 {
0%,50% {transform-origin: 50% 50%;}
0%,25% {transform: rotate(0deg);}
50% {transform: rotate(180deg);}
50.1%,100% {transform-origin: 75px 50%;}
100% {transform: rotate(540deg);}
}
</style>
</head>
<body>
<div class="loading">
<div></div>
<div></div>
</div>
</body>
</html>
解説
HTMLは以下の通りです。
<div class="loading">
<div></div>
<div></div>
</div>
まずはいつもどおり中央に寄せましょう。
body {
background: #333;
display: grid;
height: 100vh;
margin: 0;
place-items: center center;
}
今回はflex
ではなく、grid
で中央寄せを行います。特に意味はなく気分です。
-
div
の両端に疑似要素を作成 - ネガティブマージンを付けて
div
同士を重ねる -
transform-origin
を設定 - animationで回転
の3ステップで実装していきます。
まずは.loading
のサイズを考えていきましょう。
今回球のサイズは50px
、同じく隙間も50px
とします。
球が4つと、隙間が3つなのでwidth
は350px
となります。
.loading {
width: 350px;
height: 50px;
display: flex;
}
同様の考え方でdiv
のwidth
は250px
です。
.loading div {
width: 250px;
height: 50px;
position: relative;
}
次に、疑似要素を作成します。
.loading div::before,
.loading div::after {
content: "";
display: block;
width: 50px;
height: 50px;
background: rgba(0, 231, 255, 1);
border-radius: 50%;
position: absolute;
}
.loading div::after {right: 0;}
.loading div:nth-child(2) {margin-left: -150px;}
ここまで書くと、おそらくこのようになっていると思います。
ここに'box-shadow'を付けておしゃれにしてあげましょう。
.loading div::before,
.loading div::after {
content: "";
display: block;
width: 50px;
height: 50px;
background: rgba(0, 231, 255, 1);
border-radius: 50%;
position: absolute;
+ box-shadow:
+ 0 0 5px rgba(0, 231, 255, 1),
+ 0 0 10px rgba(0, 231, 255, 1),
+ 0 0 20px rgba(0, 231, 255, 1),
+ 0 0 40px rgba(0, 231, 255, 1),
+ 0 0 80px rgba(0, 231, 255, .5),
+ 0 0 160px rgba(0, 231, 255, .2);
}
これでCSS部分は完成です。
アニメーション作成
アニメーションの作成に入る前に本題のtransform-origin
の話に移りましょう。
構文は以下の通りです。
/* 値1つの構文 /
transform-origin: 2px;
transform-origin: bottom;
/ x-offset | y-offset /
transform-origin: 3cm 2px;
/ x-offset-keyword | y-offset /
transform-origin: left 2px;
/ x-offset-keyword | y-offset-keyword /
transform-origin: right top;
/ y-offset-keyword | x-offset-keyword /
transform-origin: top right;
/ x-offset | y-offset | z-offset /
transform-origin: 2px 30% 10px;
/ x-offset-keyword | y-offset | z-offset /
transform-origin: left 5px -3px;
/ x-offset-keyword | y-offset-keyword | z-offset /
transform-origin: right bottom 2cm;
/ y-offset-keyword | x-offset-keyword | z-offset /
transform-origin: bottom right 2cm;
/ グローバル値 */
transform-origin: inherit;
transform-origin: initial;
transform-origin: unset;
主に使用するのは値2つの構文で、要素の左上を起点にx-offset
、y-offset
を指定します。
キーワード指定をすることもできるので、直感的に扱うことができます。
キーワード | 値 |
---|---|
left | 0% |
center | 50% |
right | 100% |
top | 0% |
bottom | 100% |
それではアニメーションの作成に移ります。
.loading div:nth-child(1) {animation: rotate1 ease-in-out 2s 0s infinite;}
@keyframes rotate1 {
0%,50% {transform-origin: 50% 50%;}
25% {transform: rotate(180deg);}
26%,50% {transform: rotate(180deg);}
50.1%,100% {transform-origin: 175px 50%;}
100% {transform: rotate(540deg);}
}
ここでのポイントは1点です。50.1%,100% {transform-origin: 175px 50%;}
この部分で50%
ではなく、50.1%
にしている理由は、2つめのdiv
を消して実行するとわかり易いです。
これを50%,100% {transform-origin: 175px 50%;}
に変更すると、
このようになり、transform-origin: 50% 50%;
からtransform-origin: 175px 50%;
に変化する際の移動が見えてしまいます。それでは見栄えが悪いため、.1%
の間に移動させます。しかし、それでは移動していることがバレバレなのでもう一つのdiv
にも同じようなアニメーションを付けて、隠してあげましょう。
.loading div:nth-child(2) {
margin-left: -150px;
+ animation: rotate2 ease-in-out 2s 0s infinite;
}
@keyframes rotate2 {
0%,50% {transform-origin: 50% 50%;}
0%,25% {transform: rotate(0deg);}
50% {transform: rotate(180deg);}
50.1%,100% {transform-origin: 75px 50%;}
100% {transform: rotate(540deg);}
}
これで完成でもいいんですが、おしゃれに色を変えてみましょう。
.loading {
width: 350px;
height: 50px;
display: flex;
+ animation: hue-rotate linear 4s 0s infinite;
}
@keyframes hue-rotate {
100% {filter: hue-rotate(360deg);}
}
これで完成です。
応用
応用するとこんなものもできるので、是非挑戦してみてください。
おわり
分かりにくい点等あればコメント頂きたいです。
Discussion