A partial archive of discourse.wicg.io as of Saturday February 24, 2024.

[Proposal] CSS keyframes: “via” keyword

vrugtehagel
2021-03-14

With the introduction of the Element.animate() method, animating things becomes a bit easier when it comes to things like “fade in this element I just added to the DOM” or “slide this element off-screen, and then remove it”.

However, there is still a good amount of animations that are (and should be) in a stylesheet. I never had any issues with smaller animations, but when it comes to bigger animations, I often run into the following problem.

I’m writing the animation, and let’s say it looks like

@keyframes shakeAndBlink {
    from { opacity: 1; transform: translateX(0); }
    25% { opacity: 0; transform: translateX(10px); }
    50% { opacity: 1; }
    75% { opacity: 0; transform: translateX(-10px); }
    to { opacity: 1; transform: translateX(0); }
}

then I test it, and realize it should shake a bit more. So, have to rewrite the animation to

@keyframes shakeAndBlink {
    from { opacity: 1; transform: translateX(0); }
    16.67% { opacity: 0; transform: translateX(10px); }
    33.33% { opacity: 1; }
    50% { opacity: 0; transform: translateX(-10px); }
    66.67% { opacity: 1; }
    83.33% { opacity: 0; transform: translateX(10px); }
    to { opacity: 1; transform: translateX(0); }
}

This is not very developer friendly, specifically because:

  • I have to change all the offsets except for from and to.
  • I have to approximate the offsets with decimals because I cannot specify them in an exact manner.

Hence, this is my proposal: the via keyword. Like from and to, these can be used as offsets in a keyframe animation and they linearly interpolate between the two nearest absolutely specified surrounding offsets. Basically, my initial animation would look like this:

@keyframes shakeAndBlink {
    from { opacity: 1; transform: translateX(0); }
    via { opacity: 0; transform: translateX(10px); }
    via { opacity: 1; }
    via { opacity: 0; transform: translateX(-10px); }
    to { opacity: 1; transform: translateX(0); }
}

This would make adding and removing keyframes a breeze, because you only need to think about the properties. Since it’s just linear interpolation, I could also do something like this:

@keyframes blinkWiggleAndFade {
from { opacity: 1; transform: rotate(0deg); }
via { opacity: 0; transform: rotate(-20deg); }
via { opacity: 1; }
via { opacity: 0; transform: rotate(20deg); }
20% { opacity: 1; transform: rotate(0deg); }
to { opacity: 0; }
}

Where the via offsets would be equivalent to 5%, 10% and 15%.

What are your thoughts on this?