JINMUSOFTWARE

CSSアニメーションをリスタートする方法

JavaScript

CSSアニメーションをリスタートさせる方法は、アニメーション用のCSSを一旦削除し、再度追加する必要がある。

リスタート的なメソッドは無い。

結論

CSS変更時のスタイル再計算を考慮する為、requestAnimationFrame()を2段で呼び出して、2段目でアニメーション用のCSSを追加する。

結果、アニメーションのリスタートが発生する。

アニメーションCSSのサンプル

html

<div id="ani-div" class="animation">●</div>

css

.animation {
    animation-name: animation;
    animation-duration: 2s;
    animation-iteration-count: 5;
    animation-timing-function: linear;
    animation-direction: alternate;
    animation-fill-mode: forwards;
}
@keyframes animation {
    0% {
        color: yellow;
        transform: translateX(0);
    }
    100% {
        color: chartreuse;
        transform: translateX(280px);
    }
}

リスタートのデモ



( : animationクラスが外れた状態 )

CSSを削除してすぐにCSSを追加する

手動のトグルSW。CSSの削除や追加をする。

CSSを削除し、requestAnimationFrame()メソッドを使用してCSSを追加する。

CSSを削除し、requestAnimationFrame()メソッドを2段使用してCSSを追加する。

( ● : animationクラスが外れた状態 )

toggle-auto CSSを削除してすぐにCSSを追加する

toggle-sw 手動のトグルSW。CSSの削除や追加をする。

requestAnimationFrame1 CSSを削除し、requestAnimationFrame()メソッドを使用してCSSを追加する。

requestAnimationFrame2 CSSを削除し、requestAnimationFrame()メソッドを2段使用してCSSを追加する。

toggle-auto

アニメーションCSS(.animation)を削除して、すぐにCSSを追加(戻し)している。wait的なものはなし。

結果: NG。アニメーションはリスタートしなかった。

理由: CSS削除後のスタイル再計算前にCSSが戻っているので次の再描画に影響していない。

let toggle_auto_f = () => {
    const aniDiv = document.getElementById("ani-div");
    aniDiv.classList.remove('animation');
    aniDiv.classList.add('animation');
}

toggle-sw

手動のtoggleスイッチ

結果: OK。手動であればアニメーションのリスタート可能

CSSを削除するとアニメーションは停止する。CSSを追加するとアニメーションが最初から開始される。

アニメーションが削除される。停止とは違う。

let toggle_sw_f = (e) => {
    const aniDiv = document.getElementById("ani-div");
    aniDiv.classList.toggle("animation");
};

requestAnimationFrame(callback)

requestAnimationFrame()はcallbackされる関数を1つ引数に指定できる。

requestAnimationFrame()は、次の再描画の前に、アニメーションの更新要求とcallback関数を実行する。

このテストは、Firefox、Chrome で、実行結果が異なった。(2023年9月)

  • Chrome v117: リスタート可能
  • Firefox v118: リスタート不可
  • Edge v117: リスタート可能
let reqfm1_f = () => {
    const aniDiv = document.getElementById("ani-div");
    aniDiv.classList.remove('animation');
    window.requestAnimationFrame((time1) => {
        aniDiv.classList.add('animation');
    });
};

requestAnimationFrame(callback)*2

スタイル変更時の再計算を考慮して、requestAnimationFrame()の呼び出し中にrequestAnimationFrame()をもう一度呼び出す。この2回目でCSSを追加する

結果: OK

callback関数は、次の再描画の直前に実行される。

この間、再描画されていないはずなので、スタイルは再計算はされていない。

2回目の呼び出しは、スタイルの計算、再描画が実行された次の描画なので、意図したリスタートが実行される。

CSSの削除が画面に反映されアニメーションがリセットされ、CSSが戻されアニメーションがスタートする。

let reqfm2_f = () => {
    const aniDiv = document.getElementById("ani-div");
    aniDiv.classList.remove('animation');
    window.requestAnimationFrame((time1) => {
        window.requestAnimationFrame((time2) => {
            aniDiv.classList.add('animation');
        });
    });
}

以上。

参考資料

CSS アニメーションのヒントとコツ

Window.requestAnimationFrame()

参考記事

requestAnimationFrame()について

CSSアニメーションを区切りよく停止する方法

CSSアニメーションの説明