Случайное время CSS анимации на каждой итерации - PullRequest
2 голосов
/ 27 мая 2019

Попытка установить случайное время анимации на каждой итерации.Я установил пользовательское свойство CSS --animation-time, которое произвольно изменялось при каждой итерации анимации с помощью JS.

let square = document.getElementById('square');
let time;

square.addEventListener('animationiteration', duration);

function duration() {
  time = Math.random() + 1;
  square.style.setProperty('--animation-time', time + 's');
  console.log(time);
}
:root {
  --animation-time: 5s;
  --color-1: #ff0000;
  --color-2: #ffee00;
}

@keyframes fire {
  0% {
    background-color: var(--color-1);
  }
  100% {
    background-color: var(--color-2);
  }
}

#square {
  width: 100px;
  height: 100px;
  animation: fire var(--animation-time) ease alternate infinite;
}
<div id="square"></div>

Продолжительность анимации установлена ​​на time = Math.random() + 1;, поэтому итерации никогда не должны иметь менее 1 секунды.Однако иногда это происходит очень быстро.Почему?

Вот кодовая ручка: https://codepen.io/aitormendez/pen/YbvvKw

1 Ответ

2 голосов
/ 27 мая 2019

Когда вы измените animation-duration, вы не просто измените, как будет проходить каждая итерация, но вы измените всю анимацию. Например, если у вас есть 3s как длительность, поэтому первая итерация займет 3s, а если в 3s (iterationend) вы измените на 5s, это похоже на создание другой анимации, где итерация будет длиться 5 с, и вы прыгаете в новое состояние этой новой анимации, которая 3s из 5s.

Вот пример, чтобы лучше проиллюстрировать проблему. Я буду продолжать увеличивать продолжительность, и вы заметите, что как только вы достигнете конца итерации, вы вернетесь в предыдущее состояние, потому что вы увеличили продолжительность, затем вы снова достигнете последнего состояния и вернетесь назад и так далее.

Это похоже на то, что кто-то бежит в состояние 100%, и вы продолжаете увеличивать это состояние.

let square = document.getElementById('square');
let time = 1;

square.addEventListener('animationiteration', duration);

function duration() {
  time*=2;
  square.style.setProperty('--animation-time', time + 's');
  console.log(time);
}
:root {
  --animation-time: 1s;
}

@keyframes fire {
  0% {
    background-color: red;
  }
  50% {
    background:yellow;
  }
  100% {
    background-color: black;
  }
}

#square {
  width: 100px;
  height: 100px;
  animation: fire var(--animation-time) ease infinite alternate;
}
<div id="square"></div>

В приведенном выше примере я умножаю длительность на 2, поэтому каждый раз, когда я возвращаюсь назад, чтобы перейти из состояния 50%, и как только я достигаю 100%, я повторяю то же самое снова.


То же самое происходит с вашим кодом, но более сложным способом, так как вы увеличиваете / уменьшаете продолжительность. Уменьшение длительности заставит вас перейти к следующей итерации и альтернативному состоянию.

Другими словами, вы закончите со случайной мерцающей анимацией.

Чтобы наглядно проиллюстрировать, что здесь происходит, это анимация, в которой я буду анимировать временную шкалу вашей анимации

.box {
  height:50px;
  border:1px solid;
  background:
    /* This will illustrate the current state */
    linear-gradient(green,green) left/2px 100% no-repeat,
    /* This is our animation with a duration of 5s (50px) intially*/
    linear-gradient(to right,yellow,red,red,yellow) left/100px 100%;
   
  animation:
    move 10s linear infinite, /* This is the current state*/
    change 2s steps(3) infinite /* this is the change of the animation duration*/
  ; /**/
}

@keyframes move {
  to {
    background-position:right,left;
  }
}
@keyframes change {
  to {
    background-size:2px 100%,40px 100%;
  }
}
<div class="box">

</div>

Вы можете видеть, что мы не меняем текущее состояние (показано зеленой линией), но мы меняем всю анимацию, делая текущее состояние случайным образом переходящим в другой цвет.


Одна идея, чтобы получить то, что вы хотите, это рассмотреть переход и переключение классов:

let square = document.getElementById('square');
let time;

/* We intially add the class to trigger the transition*/
setTimeout(function(){square.classList.toggle('change')},10);

square.addEventListener('transitionend', duration);

/* When the transition is done we toggle the class to start another one*/
function duration() {
  time = Math.random() + 1;
  square.style.setProperty('--animation-time', time + 's');
  square.classList.toggle('change');
  console.log(time);
}
:root {
  --animation-time: 1s;
  --color-1: #ff0000;
  --color-2: #ffee00;
}

#square {
  width: 100px;
  height: 100px;
  transition: var(--animation-time) ease;
  background-color: var(--color-1);
}

#square.change {
  background-color: var(--color-2);
}
<div id="square"></div>
...