Я пытаюсь создать CSS-анимацию, которая прыгает вперед и назад с паузой на каждом конце. Использование Javascript-метода element.animate(), похоже, помогает, за исключением того, что использование ключевых кадров нарушает функцию плавности, чего не происходит при использовании только CSS.
Я неправильно использую animate()? Это ошибка? Почему Javascript и CSS ведут себя по-разному? В документации animate MDN об этом ничего не сказано.
const element = document.getElementById("animation")
const anim = element.animate(
[
{ offset: 0, transform: "translateX(0)" },
{ offset: .1, transform: "translateX(0)" },
{ offset: .9, transform: "translateX(50vw)" },
{ offset: 1, transform: "translateX(50vw)" },
],
{
duration: 5000,
easing: "ease-in-out",
direction: "alternate",
iterations: Infinity,
}
);
<div id = "animation">Ball</div>
Создание такой же анимации в CSS работает при правильном замедлении.
const element = document.getElementById("animationJS")
const anim = element.animate(
[
{ offset: 0, transform: "translateX(0)" },
{ offset: .1, transform: "translateX(0)" },
{ offset: .9, transform: "translateX(50vw)" },
{ offset: 1, transform: "translateX(50vw)" },
],
{
duration: 5000,
easing: "ease-in-out",
direction: "alternate",
iterations: Infinity,
}
);
#animationCSS {
animation-name: move;
animation-direction: alternate;
animation-duration: 5s;
animation-timing-function: ease-in-out;
animation-iteration-count: infinite;
}
@keyframes move {
from {
transform: translateX(0);
}
10% {
transform: translateX(0);
}
90% {
transform: translateX(50vw);
}
to {
transform: translateX(50vw);
}
}
<div id = "animationJS">Ball1</div>
<div id = "animationCSS">Ball2</div>
Однако я не могу использовать CSS, потому что хочу, чтобы проценты/смещения ключевых кадров изменялись программно.
Кроме того, удаление двух средних ключевых кадров в JS-коде исправляет ситуацию, но это все равно не то, что мне нужно.
@somethinghere Хорошо, я понимаю, что ты имеешь в виду. Кажется, оно действительно ускоряется. Однако поведение заметно отличается от поведения CSS: оно запускается и останавливается с гораздо большей скоростью при тех же числах. Вот почему я подумал, что облегчение выхода не работает. Я до сих пор озадачен несоответствием. Вот код для воспроизведения, просто удалите JS-файл и посмотрите, как значительно изменится анимация.
Просто превратил ваш CSS во фрагмент, и нет, они выглядят совершенно одинаково. И они должны! Я добавил объединенную версию в свой ответ ниже, и анимация замедления выглядит почти так же, поэтому здесь мешает что-то еще. Ослабление работает так, как ожидалось (если это не так и никто, кроме вас, не заметил? Это маловероятно...)
@somethinghere Я добавил код JS во фрагмент CSS. Разница в анимации между ними очевидна, без различий в параметрах. Кажется, что чистый CSS применяет функцию замедления к пошаговой анимации, в то время как код JS применяет функцию замедления ко всей анимации, как вы упомянули. Мне кажется, что в реализации JS есть ошибка или недокументированное поведение. О, вы объединили их в своем ответе. Дело в том, что я хочу отсрочки... Так что странность остается.
Могу ли я дать еще одну подсказку: снимите пометку с моего ответа как «ответ», чтобы ваш вопрос не был завершен и вы могли бы привлечь людей, которые знают то, чего не знаем мы? (Я имею в виду, возможно, проголосуем за это в ответ, но в любом случае это нормально — просто хочу, чтобы вы нашли решение!)
О, я не знал, что отметка ответа помешает его обнаружить. Я проголосовал за вас, но у меня недостаточно репутации, чтобы это учитывалось :( к сожалению, новый аккаунт.
Все хорошо. Это не прописанное правило, но когда ответ помечается как правильный, даже я начинаю игнорировать вопросы, так как не обязательно что-то добавлять. Удачи!
Если вы удалите какие-либо сбивающие с толку аспекты анимации (поскольку замедление охватывает весь диапазон значений, поэтому оно начинается с 0 и заканчивается на 1, это означает, что вы пропускаете первые 10% замедления и последние 10 % части замедления) и немного увеличьте значения, чтобы действительно увидеть замедление в действии, вы заметите, что в настоящее время оно работает так, как ожидалось. В анимации легко запутаться, особенно если она тонкая.
const element = document.getElementById("animation")
const anim = element.animate(
[
{ offset: 0, transform: "translateX(0)" },
{ offset: 1, transform: "translateX(100vw) translateX(-100%)" },
],
{
duration: 5000,
easing: "ease-in-out",
direction: "alternate",
iterations: Infinity,
}
);
#animation { position: absolute; left: 0; top: 0; }
<div id = "animation">Ball</div>
Вы можете увидеть это в приведенном выше фрагменте: ускориться, замедлиться: ease-in-out
работает как положено. Я понимаю, чего вы пытаетесь достичь, имея 20%-ный перерыв между временными шкалами анимации, используя одну временную шкалу, но, насколько я понимаю, замедление применяется ко всей вашей временной шкале. Поэтому из-за этого вам может потребоваться настроить бесконечный цикл, чтобы добавить задержку:
async function delay( ms ){
return new Promise(r => setTimeout(r, ms));
}
async function loopAnimation(){
const element = document.getElementById("animation")
let direction = 'normal';
let animation;
while( true ){
await delay(1000);
// Make sure previous an animations are removed and don't stack up
if ( animation ) animation.cancel();
animation = element.animate([
{ offset: 0, transform: "translateX(0)" },
{ offset: 1, transform: "translateX(100vw) translateX(-100%)" },
],{
duration: 3000,
easing: "ease-in-out",
direction: direction,
iterations: 1,
fill: 'both'
})
await animation.finished;
await delay(1000);
// Reverse the animation
direction = direction === 'normal' ? 'reverse' : 'normal';
}
}
loopAnimation();
#animation { position: absolute; left: 0; top: 0; }
<div id = "animation">Ball</div>
Как вы можете видеть ниже, анимации на 99% одинаковы, я полагаю, что разница заключается лишь в небольшой разнице во времени с JS и загрузке, но они работают почти одинаково (мне пришлось исправить вашу анимацию в JS, чтобы она была .9
, а не .8
в качестве смещения):
const element = document.getElementById("animate-js")
const anim = element.animate(
[
{ offset: 0, transform: "translateX(0)" },
{ offset: .1, transform: "translateX(0)" },
{ offset: .9, transform: "translateX(10vw)" },
{ offset: 1, transform: "translateX(10vw)" },
],
{
duration: 5000,
easing: "ease-in-out",
direction: "alternate",
iterations: Infinity,
}
);
#animate-css {
animation-name: move;
animation-direction: alternate;
animation-duration: 5s;
animation-timing-function: ease-in-out;
animation-iteration-count: infinite;
color: red;
}
@keyframes move {
from {
transform: translateX(0);
}
10% {
transform: translateX(0);
}
90% {
transform: translateX(10vw);
}
to {
transform: translateX(10vw);
}
}
<div id = "animate-js">Animate</div>
<div id = "animate-css">Animate</div>
На самом деле нет, странность все равно в том, что вы пытаетесь добавить задержку в цикл:
const element = document.getElementById("animate-js")
const anim = element.animate(
[
{ offset: 0, transform: "translateX(0)" },
{ offset: 1, transform: "translateX(10vw)" },
],
{
duration: 5000,
easing: "ease-in-out",
direction: "alternate",
iterations: Infinity,
}
);
#animate-css {
animation-name: move;
animation-direction: alternate;
animation-duration: 5s;
animation-timing-function: ease-in-out;
animation-iteration-count: infinite;
color: red;
}
@keyframes move {
from {
transform: translateX(0);
}
to {
transform: translateX(10vw);
}
}
<div id = "animate-js">Animate</div>
<div id = "animate-css">Animate</div>
Без этого они идеально синхронизированы.
Это работает, большое спасибо! Хотя это гораздо сложнее, чем должно быть. Тот факт, что замедление применяется шаг за шагом с использованием CSS и в целом анимация с использованием JS, кажется большим упущением. Я обновил свой первоначальный вопрос фрагментами, которые четко иллюстрируют разницу между ними, с тем же набором параметров.
Примечание: вам не обязательно отмечать это как правильный ответ, однако любопытно, что вы упомянули об этой разнице. Мне интересно, имеет ли это какое-либо отношение к таким вещам, как составная система в JS, которую CSS не поддерживает?
Я нашел решение — соответствующий JS-код, который работает так же, как и CSS.
const element = document.getElementById("animationJS")
const anim = element.animate(
[
{ offset: 0, transform: "translateX(0)" },
{ offset: .1, transform: "translateX(0)", easing: "ease-in-out" },
{ offset: .9, transform: "translateX(50vw)"},
{ offset: 1, transform: "translateX(50vw)" },
],
{
duration: 5000,
direction: "alternate",
iterations: Infinity,
}
);
#animationCSS {
animation-name: move;
animation-direction: alternate;
animation-duration: 5s;
animation-timing-function: ease-in-out;
animation-iteration-count: infinite;
}
@keyframes move {
from {
transform: translateX(0);
}
10% {
transform: translateX(0);
}
90% {
transform: translateX(50vw);
}
to {
transform: translateX(50vw);
}
}
<div id = "animationJS">Ball1</div>
<div id = "animationCSS">Ball2</div>
Добавление функции замедления только к средней части анимации и удаление ее из всей анимации дает результат.
Я понятия не имею, почему это так работает, и не могу найти этой конкретной разницы в документации, но, по крайней мере, это работает.
Хорошо, я превратил это в фрагмент. Вы уверены, что вас не смущает тот факт, что эта задержка встроена в вашу анимацию? Потому что похоже, что он делает именно то, что и ожидалось, плавно входя и выходя, но с вашими нынешними ценностями это может и не обязательно выглядеть так. Чтобы быть на 100% уверенным: увеличьте анимацию (сделайте ее
100vw
или1000px
) и удалите все сбивающие с толку аспекты, чтобы увидеть, делает ли замедление то, что вы ожидаете (в этом случае удалите ключевые кадры.1
и.9
, чтобы убедиться в правильности замедления). считает все время). Но в настоящее время: невозможно воспроизвести.