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