🤖
animationendとtransitionendを使って複数要素にちょっと複雑な動きをさせる
概要
- なんかちょっと複雑なアニメーションを頼まれた時に、楽していい感じにかけないかなぁと思った
-
@keyframes
の%指定だけだとタイミングとかが微妙にずれることもあるし、ちょっとだるいなぁ - せや、
animationend
とtransitionend
使って別々の関数発火させればコントロール可能なんちゃうか??
動作確認
code
index.html
index.html
<div class="s500 bg-lightgray f fh">
<div id='container' class="relative s200 bg-black f fh">
<div class=' text-white fs24 bold'>
END
</div>
<div id='item1' class="absolute t0 l0 bg-red s-full f fh text-white fs24 bold overflow-hidden transition-1024">
item 1
</div>
<div id='item2' class="absolute t0 l0 bg-blue s-full f fh text-white fs24 bold overflow-hidden transition-1024">
item 2
</div>
<div id='item3' class="absolute t0 l0 bg-green s-full f fh text-white fs24 bold overflow-hidden transition-1024">
item 3
</div>
</div>
</div>
main.css
main.css
.animation-1 {
animation-name: scale;
animation-duration: 3s;
animation-timing-function: ease-out;
animation-fill-mode: forwards;
}
@keyframes scale {
from {
transform: scale(1.0);
}
to {
transform: scale(1.5);
}
}
main.js
main.js
window.onload = function() {
var $item1 = document.getElementById('item1');
var $item2 = document.getElementById('item2');
var $item3 = document.getElementById('item3');
var items = [$item1, $item2, $item3];
setDefault(items);
setAnimationEnd(items);
setTransitionEnd(items);
};
// 初期クラスをセットする
var setDefault = (items) => {
var arr = Array.isArray(items) ? items : Array.from(items);
arr.forEach((item, index) => {
switch (index) {
case 0:
item.classList.add('z3', 'animation-1');
break;
case 1:
item.classList.add('z2');
break;
case 2:
item.classList.add('z1');
break;
}
});
};
// animation終了時のイベントに関数を登録する
var setAnimationEnd = (items) => {
var arr = Array.isArray(items) ? items : Array.from(items);
arr.forEach((item, index) => {
item.onanimationend = onAnimationEnd;
});
};
// アニメーション終了時にトランジションさせるためのクラス付け替え
var onAnimationEnd = (e) => {
e.currentTarget.classList.remove('s-full');
e.currentTarget.classList.add('s0');
console.log('animation end');
};
// transition終了時のイベントに関数を登録する
var setTransitionEnd = (items) => {
var arr = Array.isArray(items) ? items : Array.from(items);
arr.forEach((item, index) => {
item.ontransitionend = onTransitionEnd;
});
};
// トランジション終了時に次の要素のアニメーションを始めるための関数を呼ぶ
var onTransitionEnd = (e) => {
console.log('transition end');
var next = e.currentTarget.nextElementSibling;
if (!next) return ;
setNextItem(next);
};
// アニメーションを開始するクラスをつける
var setNextItem = (item) => {
item.classList.add('animation-1');
};
解説
流れ
- 一個目の要素が大きくなるアニメーションを始める
- 大きくなるアニメーションが終わり次第、大きさを小さくしていく
- 大きさが0になったら、次の要素のアニメーションを始める
- 上を要素がなくなるまで繰り返す
onanimationend
- animationが終了した時に発火するイベント
- @keyframesで登録したアニメーションの場合は、こちらが発火する
- 今回で言うと要素が3秒間かけてscale(1.5)になるアニメーション
- 1.5倍になったらonanimationendが発火する
ontransitionend
- transitionが終了した時に発火するイベント
- 今回で言うと
.transition-1024
というクラスをつけており、1024msかけて要素が変わるようにしている - widthとheightが100%の状態から、0pxにするというトランジション
- 0pxになったらontransitionendが発火する
まとめ
- 多分アニメーションのプロフェッショナルの方はこんなんやらなくてもanimation-timing-functionのcubic-bezierとかで完璧なタイミングのアニメーションが作れるかもしれないが、自分は力不足だったので、こんな感じになった
- onAnimationEnd関数の中でまたいろいろやれば、次の要素が見えた時にアニメーション始めたり、文字出したり、いろいろできるけど、今回は省略
- onTransitionEnd関数の中でもっといい感じにやれば上記アニメーションを無限に繰り返すこともできるが、今回は省略
- そしていつもながら見た目やアニメーション名がクソ適当なのはご容赦ください。
Discussion