I'm trying to make a CSS animation that bounces back and forth, with a pause at each end. Using the Javascript method element.animate() seems to do the trick, except that using keyframes breaks the easing function, which doesn't happen when using only CSS.
Am I using animate() wrong? Is it a bug? Why do Javascript and CSS behave differently? The animate MDN docs don't say anything about this.
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>
Creating the same animation in CSS works with the correct easing.
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>
However, I can't use CSS because I want the keyframe percentages/offsets to be changed programmatically.
Also, removing the middle two keyframes in the JS code fixes it, but it still isn't what I want.
I've found the solution, the corresponding JS code that works the same as the CSS one.
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>
Adding the easing function only to the middle part of the animation and removing it from the whole does the trick.
I have no idea why it works like this, and I can't find this specific difference in the documentation, but at least it works.