CSSアニメーションやトランジションが終わったタイミングで処理を実行したい場合、animationend・transitionend イベントを使います。この記事では基本的なイベント検知・複数要素の完了待ち・Promise化・よくある落とし穴まで解説します。
この記事でわかること
- animationend / transitionend イベントの基本的な使い方
- アニメーション後に要素を削除・クラス変更する
- 複数要素のアニメーション全完了を待つ
- トランジション終了後の処理をPromise化する
- 注意点:イベントが発火しないケースや複数回発火
animationend / transitionend の基本
| イベント | 発火タイミング | 対象 |
|---|---|---|
animationend |
CSSアニメーション(@keyframes)終了時 | animation: xxx を持つ要素 |
transitionend |
CSSトランジション終了時 | transition: xxx を持つ要素 |
animationstart |
アニメーション開始時 | 同上 |
animationiteration |
繰り返しアニメーション1周ごと | 同上 |
$(function () {
// CSSトランジション終了後に処理
$('#box').on('transitionend', function () {
console.log('トランジション終了');
$(this).addClass('is-done');
});
// CSSアニメーション(@keyframes)終了後に処理
$('#box').on('animationend', function () {
console.log('アニメーション終了');
$(this).remove(); // アニメーション後に要素を削除
});
// トリガー: クラスを付けてアニメーション開始
$('#start-btn').on('click', function () {
$('#box').addClass('is-animating');
});
});
一度だけ発火させる(.one()の活用)
transitionend は複数のプロパティがトランジションする場合、プロパティごとに発火します。一度だけ処理したい場合は .one() を使います。
$(function () {
// .one() で一度だけ実行
$('#box').one('transitionend', function () {
console.log('1回だけ実行');
});
// または off() で手動解除
function onTransitionEnd() {
console.log('トランジション終了');
$(this).off('transitionend', onTransitionEnd);
}
$('#box').on('transitionend', onTransitionEnd);
});
transitionend は複数プロパティ分発火する
transition: color 0.3s, transform 0.3s のように複数プロパティを持つ場合、transitionend は2回発火します。.one() を使うか、event.propertyName で特定プロパティの終了だけを処理してください。特定プロパティのトランジション終了を検知する
$(function () {
$('#box').on('transitionend', function (e) {
// transformのトランジションが終わったときだけ処理
if (e.originalEvent.propertyName !== 'transform') return;
console.log('transformトランジション終了');
$(this).addClass('transform-done');
});
});
複数要素のアニメーション完了を全て待つ
$(function () {
var $items = $('.animated-item');
var doneCount = 0;
$items.on('animationend', function () {
doneCount++;
if (doneCount === $items.length) {
console.log('全要素のアニメーション完了');
showNextSection();
}
});
// クラスを付けてアニメーション開始
$items.addClass('is-animating');
});
トランジション終了後の処理をPromise化する
function waitForTransition($el) {
return new Promise(function (resolve) {
$el.one('transitionend', function (e) {
resolve(e);
});
});
}
$(function () {
// async/await で順次処理
async function runSequence() {
// 1. フェードアウト
$('#box').addClass('is-fading');
await waitForTransition($('#box'));
// 2. コンテンツを変更
$('#box').text('新しいコンテンツ').removeClass('is-fading').addClass('is-visible');
await waitForTransition($('#box'));
console.log('シーケンス完了');
}
$('#start-btn').on('click', runSequence);
});
Promise化で非同期アニメーションを同期的に書ける
コールバックのネストを避けてasync/awaitで順次処理が書けます。ただしjQueryの
コールバックのネストを避けてasync/awaitで順次処理が書けます。ただしjQueryの
.animate() の場合はjQueryオブジェクトのPromiseとして.promise().done(fn) が使えます。まとめ
CSSアニメーション/トランジション終了検知のポイントをまとめます。
- CSSアニメーション:
animationendイベント - CSSトランジション:
transitionendイベント - 一度だけ:
.one("transitionend", fn) - 複数プロパティ:
event.originalEvent.propertyNameで絞り込み - 複数要素の完了待ち: カウンター変数で全完了を検知
関連記事: slideToggle()がカクつく原因と対処法 / 要素をフェードイン・フェードアウトさせる方法
よくある質問(FAQ)
Qtransitionendが発火しません。
A主な原因は3つです。①要素にtransitionが設定されていない。②CSSの変化がない(クラスを付けても既に同じスタイルだった)。③アニメーション対象のプロパティが途中でキャンセルされた(transition中に別のクラスが付いた等)。ブラウザの開発者ツールのアニメーションパネルで確認してください。
QCSSアニメーションの途中でキャンセルしたときのイベントはどうなりますか?
Aアニメーション途中でクラスを削除するとアニメーションがキャンセルされ、
animationend は発火しません。キャンセル時に処理したい場合は animationcancel イベントを使ってください(最新ブラウザのみ)。または transitioncancel がトランジションのキャンセル時に発火します。QjQueryの.animate()はanimationendで検知できますか?
AjQueryの
.animate() はCSSアニメーションではなくJavaScriptアニメーションなので、animationend は発火しません。.animate(props, duration, callback) のコールバック引数を使ってください。または $(el).animate({...}).promise().done(fn) でPromise対応できます。Qアニメーションが繰り返す場合に終了を検知したいです。
A
animation-iteration-count: infinite の場合は animationend が発火しません。特定回数で止めたい場合は animationiteration でカウントして、N回目に animation-play-state: paused にする方法か、animation-iteration-count: 3 のように有限回数を指定してください。QWeb Animations API との使い分けは?
AWeb Animations API(WAAPI)は
el.animate(keyframes, options) でJavaScriptからアニメーションを制御できる標準APIです。animation.finished(Promise)でアニメーション完了を待てるため、animationend イベントより扱いやすいケースもあります。ただし古いブラウザでは非対応です。

