この記事はun-T factory! XA Advent Calendar 20218日目の記事です・
概要
こんにちは、最近オフィスの一画にカフェ&バーが完成し、営業許可証と食品衛生責任者の資格を取りに行った、フロントエンドエンジニアの茂吉です。
今回はCSSのanimationとkeyframesについて話したいと思います。
CSSアニメーションにはtransitionとanimationの2つがあり、CSSで複雑なアニメーションを実装する場合、animationプロパティを駆使して表現することが多いのではないでしょうか。
キーフレームを使うことで自由に表現することができる反面、一つのkeyframesに詰め込みすぎてしまうと、どのキーフレームで何のアニメーションをしているかがわかりづらくなります。
本記事は、CSSのkeyframesを表現ごとに分割することで可読性を高め、汎用性を持たせつつメンテンナンスしやすくする方法を説明していきたいと思います。
この記事で伝えたいこと
- キーフレームを整理することで可読性を高められる
- animationの値を分割することで汎用性を持たせることができる
- キーフレームごとにイージングやdurationを柔軟に調整することができる
分かりづらいkeyframesの例
一つのkeyframesに詰め込んだ場合の記述を例に説明していきます。
例はリンゴが実った後に地面に向かって落下し、弾むというものです。
See the Pen animation keyframes sample3 by seiya kato (@mokichi) on CodePen.
下記のようにkeyframesが一つにまとまっていることで、どのキーフレームが何の表現をしているのかがひと目ではわかりづらく、部分的な調整がとても大変です。
(keyframsの中身はサラッと読み飛ばしてください。)
.dropBounce {
animation: dropBounce 1.8s $easeInOutSine forwards;
}
// 【Keyframes】 落下して弾む
@keyframes dropBounce {
0% {
transform: scale(0);
}
13% {
transform: scale(1.5);
}
23% {
transform: scale(0.8);
}
30% {
transform: scale(1.1);
}
33% {
transform: scale(1);
}
33.001% {
top: 0;
animation-timing-function: $easeInQuart;
}
56%,56.001% {
top: 200px;
}
62% {
top: 190px;
}
66% {
top: 200px;
}
71% {
top: 195px;
}
74% {
top: 200px;
}
77% {
top: 198px;
}
80%, 100% {
top: 200px;
}
}
キーフレーム名だけで表現がわかるように整理する
まずは落下と弾むという2つの動きに絞って説明していきます。
dropとbounceというキーフレーム名にして、animationの値を設定します。
animationの値をカンマ区切りにすることで、複数のkeyframesを繋げて指定することができます。
- 落下(drop)
- 弾む(bounce)
.dropBounce {
animation:
drop 0.6s $easeInQuart forwards,
bounce 0.6s $easeOutSine forwards 0.6s
;
}
// 【Keyframes】 落下
@keyframes drop {
0% {
top: 0;
}
100% {
top: 200px;
}
}
// 【Keyframes】 弾む
@keyframes bounce {
0% { top: 200px; }
10% { top: 190px; }
20% { top: 200px; }
30% { top: 195px; }
40% { top: 200px; }
50% { top: 198px; }
55% { top: 200px; }
}
$easeInQuart
や$easeOutSine
はイージングの変数で、ベジェ曲線というものを利用して動きの緩急を付けるのですが、イージングについては以前記事で書いた
【CSSアニメーション】transitionのイージングにease-inやease-outを適当に設定するのはやめましょうを読んでいただければと思います。
forwards
はanimation-fill-mode
プロパティの値で、最後のキーフレームで停止する指定です。
keyframes名の後ろの0.6s
はanimation-duration
で0.6秒かけてアニメーションをするという指定です。forwardsの後ろの0.6s
はanimation-delay
で0.6秒後にbounceが始まります。
See the Pen animation keyframes sample1 by seiya kato (@mokichi) on CodePen.
汎用性を持たせるキーフレームを作成する
ここからは**落下(drop)して弾む(bounce)**をベースに、実る
や横移動
、転がる
、潰れる
などを追加して3パターン作成してみます。
dropやbounce、途中で登場するkeyframesは割愛して説明します。
実って落ちる
リンゴが実るようなアニメーションを先頭に追加します。
keyframes名はgrowとします。
- 実る(grow)
実る演出のanimation-durationは0.6s
なので、dropやbounceにはanimation-delayを0.6s
ずつ追加します。
See the Pen animation keyframes sample2 by seiya kato (@mokichi) on CodePen.
冒頭で挙げた「分かりづらいkeyframesの例」と見比べてみると、表現ごとにキーフレームを分割したことで可読性が高まり、キーフレームも0%〜100%で指定することができるため、追加調整時の余計な計算が不要になります。
.grow {
animation:
grow 0.6s $easeInSine forwards,
drop 0.6s $easeInQuart forwards 0.6s,
bounce 0.6s $easeOutSine forwards 1.2s
;
}
// 【Keyframes】 実る
@keyframes grow {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
70% {
transform: scale(0.8);
}
90% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}
転がる
横移動しながら転がる表現を追加してみます。
- 横移動(moveOn)
- 転がる(rollOver)
See the Pen animation keyframes sample1 by seiya kato (@mokichi) on CodePen.
今回は転がる+横移動+回転が同時進行のため、animation-delay
はbounceにしかかけません。
補足として、弾んだタイミングで回転を強くかけたいため、rollOverのイージングは変数ではなく、cubic-bezierを独自で作成しています。→ https://cubic-bezier.com/#.45,0,.42,1
.dropRollOver {
animation:
drop 0.6s $easeInCubic forwards,
moveOn 1.2s $easeInOutSine forwards,
rollOver 1.2s cubic-bezier(.46,.01,.43,1) forwards,
bounce 0.6s $easeOutSine forwards 0.6s
;
}
// 【Keyframes】 横に移動
@keyframes moveOn {
0% {
left: 0px;
}
100% {
left: 200px;
}
}
// 【Keyframes】 回転
@keyframes rollOver {
0% {
transform: rotate(0deg);
}
50% {
transform: rotate(50deg);
}
90% {
transform: rotate(315deg);
}
100% {
transform: rotate(320deg);
}
}
潰れる
最後に実って落下したら潰れるという演出を加えてみます。
- 潰れる(break)
See the Pen animation keyframes sample3 by seiya kato (@mokichi) on CodePen.
.dropBreak {
animation:
grow 0.6s $easeInSine forwards,
drop 0.6s $easeInQuart forwards 0.6s,
break 0.1s $easeOutExpo forwards 1.2s
;
}
// 【Keyframes】 落下後のバウンド
@keyframes break {
0% {
transform-origin: center center;
transform: scale(1, 1);
}
50% {
transform-origin: center bottom;
}
100% {
transform-origin: center bottom;
transform: scale(2, 0.04);
}
}
まとめ
- keyframesに複数のアニメーションを詰め込みすぎない
- キーフレーム名だけで表現がわかるようにまずは整理する
- animationの値はカンマで区切り、複数のkeyframeを繋げる
- キーフレームを分割することで可読性が高まり、メンテナンス性も向上する