Oteto Blogのロゴ

【CSS】アニメーションで繰り返しごとに間隔を空ける方法

やりたいこと

CSSではanimationプロパティを使ってアニメーションを付けることができます。

ではこのように「繰り返しの度に1秒待ってから動き出すようにしたい」場合はどうすればいいでしょう。

animation-delayプロパティでは繰り返せない

.circle {
  animation: circle-move 2s infinite;
  animation: circle-move 2s 1s infinite;
}

animation-delayを指定すると、その時間分アニメーションの開始を遅らせることができます。

しかしその値を1sにしても待ってくれるのは初回限りで、それ以降のループでは待たずにビュンビュン動いてしまいます。

というのもanimation-delayはあくまで初回の開始を遅らせるだけで、それ以降は遅延が発生しません。この解決法が本記事の主題です。

解決法

まず結論から。

  1. アニメーションの中で何もしない時間を作る
  2. 後続のタイミングを調整する
  3. 初回タイミングの状態を初期値にする

これだけだと理解しづらいと思うので、詳細を解説していきます。

前提

.circle {
  animation: circle-move 2s infinite;
}

@keyframes circle-move {
  20% {
    transform: scale(1.1, 0.9) translateY(40px);
  }
  40% {
    transform: scale(1) translateY(0);
  }
  60% {
    transform: scale(1.1, 0.9) translateY(40px);
  }
  80% {
    transform: scale(1) translateY(0);
  }
  100% {
    margin-left: 100%;
  }
}

今回はこのアニメーションに対して「1秒間待った後に2秒間動かすようにしたい」というケースで考えてみます。

1. アニメーションの中で何もしない時間を作る

.circle {
  animation: circle-move 2s infinite;
  animation: circle-move 3s infinite;
}

まずanimation-durationの値に、空ける間隔の時間を足します。例の場合は2 + 1なので3sですね。

<空けたい間隔の時間> / <アニメーションの総時間> * 100

次は上記の計算式をもとに、「アニメーション総時間に対する、空ける間隔の時間」の百分率を求めます。(以後この値を「割合」と呼びます)

例えば今回の場合、空けたい間隔の時間は1秒、アニメーションの総時間は3秒なので割合は33%になります。

@keyframes circle-move {
  33% {

  }
  20% {
    transform: scale(1.1, 0.9) translateY(40px);
  }
  40% {
    transform: scale(1) translateY(0);
  }
  60% {
    transform: scale(1.1, 0.9) translateY(40px);
  }
  80% {
    transform: scale(1) translateY(0);
  }
  100% {
    margin-left: 100%;
  }
}

そうしたら先ほど求めた「割合」を初回のタイミングに設定します。

2. 後続のタイミングを調整する

元のタイミングの間隔 × (1 - <割合> / 100)

それから後続の動きを「何もしない時間」を考慮したものにする必要があるので、上の計算式をもとにとある値を求めます。

例の場合は20%ずつ区切って指定していたので20 * (1 - 1 / 3) = 20 * 2 / 3となり、結果は13となります。

@keyframes circle-move {
  33% {

  }
  20% {
  46% {
    transform: scale(1.1, 0.9) translateY(40px);
  }
  40% {
  59% {
    transform: scale(1) translateY(0);
  }
  60% {
  72% {
    transform: scale(1.1, 0.9) translateY(40px);
  }
  80% {
  85% {
    transform: scale(1) translateY(0);
  }
  100% {
    margin-left: 100%;
  }
}

そうしたら、後続のタイミングを初回のタイミングに足していくように指定します。2回目は初回の33 + 13 = 46%で3回目は46 + 13 = 59%⋯といった感じですね。

しかしこのままでは初回の「何もしない時間」に動いてしまいます。

なので最後に、初回のタイミングまで動かないように修正します。

3. 初回タイミングの状態を初期値にする

@keyframes circle-move {
  33% {
    margin-left: 0;
    transform: scale(1) translateY(0);
  }
  46% {
    transform: scale(1.1, 0.9) translateY(40px);
  }
  59% {
    transform: scale(1) translateY(0);
  }
  72% {
    transform: scale(1.1, 0.9) translateY(40px);
  }
  85% {
    transform: scale(1) translateY(0);
  }
  100% {
    margin-left: 100%;
  }
}

今回のアニメーションではmargin-lefttransformの値を変化させていたので、33%のタイミングの値をそれぞれの初期値にします。

すると繰り返しごとに間隔が生まれていますね。これで完了です 🎉