I learned CSS3 @keyframes
syntax in January 2016 and, over 2 years later, I now find myself using @keyframes
animations in no small amount of my work (more sophisticated than CSS3 transitions, less cumbersome than javascript-based animations).
One thing I really miss though is the ability to express @keyframes
in seconds rather than in percentages. Are there any hacks to achieve this?
I know I can use the following 100s
hack to cycle through rainbow colors, with one cycle every 3 seconds:
div {
width: 120px;
height: 120px;
background-color: violet;
animation: myAnimation 100s;
}
@keyframes myAnimation {
0% {background-color: red;}
3% {background-color: orange;}
6% {background-color: yellow;}
9% {background-color: green;}
12% {background-color: cyan;}
15% {background-color: blue;}
18% {background-color: violet;}
100% {background-color: violet;}
}
<div></div>
But it means that the animation is still running (albeit imperceptibly) for another 82 seconds after it has (effectively) finished. Amongst other concerns, this puts multiple iterations out of reach.
What I'd really like to write is simply:
@keyframes myAnimation {
0s {background-color: red;}
3s {background-color: orange;}
6s {background-color: yellow;}
9s {background-color: green;}
12s {background-color: cyan;}
15s {background-color: blue;}
18s {background-color: violet;}
}
Is there any better approach than the one I have detailed in the code box above?
I realise in hindsight I have probably made the example above too simple given that it involves animating a single element and my question originally emerges from wanting to animate multiple elements in sync with each other.
So, here is a slightly more elaborate example, showing a set-up much closer to the one which gave rise to my question in the first place:
div {
display: inline-block;
width: 48px;
height: 48px;
margin-right: 6px;
}
div:nth-of-type(1) {
background-color: red;
}
div:nth-of-type(2) {
background-color: orange;
animation: myAnimationOrange 100s;
}
div:nth-of-type(3) {
background-color: yellow;
animation: myAnimationYellow 100s;
}
div:nth-of-type(4) {
background-color: green;
animation: myAnimationGreen 100s;
}
div:nth-of-type(5) {
background-color: cyan;
animation: myAnimationCyan 100s;
}
div:nth-of-type(6) {
background-color: violet;
animation: myAnimationViolet 100s;
}
@keyframes myAnimationOrange {
0% {background-color: white;}
1% {background-color: white;}
2% {background-color: orange;}
100% {background-color: orange;}
}
@keyframes myAnimationYellow {
0% {background-color: white;}
2% {background-color: white;}
3% {background-color: yellow;}
100% {background-color: yellow;}
}
@keyframes myAnimationGreen {
0% {background-color: white;}
3% {background-color: white;}
4% {background-color: green;}
100% {background-color: green;}
}
@keyframes myAnimationCyan {
0% {background-color: white;}
4% {background-color: white;}
5% {background-color: cyan;}
100% {background-color: cyan;}
}
@keyframes myAnimationViolet {
0% {background-color: white;}
5% {background-color: white;}
6% {background-color: violet;}
100% {background-color: violet;}
}
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
Don't forget you can run multiple animations on the same element, and that you can set their duration
, delay
and all other animation-...
rules independently.
E.g, you can split all your keyframes to single-key @keyframes rules.
Then it's easy to control when they'll kick in and to chain them.
div {
width: 120px;
height: 120px;
background-color: violet;
animation-fill-mode: forwards;
animation-name: orange, yellow, green, cyan, blue, violet;
animation-delay: 0s, 3s, 6s, 9s, 12s, 15s, 18s;
animation-duration: 3s; /* same for all */
}
@keyframes orange {
to { background-color: orange; }
}
@keyframes yellow {
to { background-color: yellow; }
}
@keyframes green {
to { background-color: green; }
}
@keyframes cyan {
to { background-color: cyan; }
}
@keyframes blue {
to { background-color: blue; }
}
@keyframes violet {
to { background-color: violet; }
}
<div></div>
In this case, you don't even need to combine multiple animations on the same element, but simply set the animation-delay
accordingly:
div {
/* same for all */
width: 60px;
height: 60px;
display: inline-block;
background-color: white;
animation-fill-mode: forwards;
animation-duration: 3s;
}
div:nth-of-type(1) {
animation-name: orange;
animation-delay: 0s;
}
div:nth-of-type(2) {
animation-name: yellow;
animation-delay: 3s;
}
div:nth-of-type(3) {
animation-name: green;
animation-delay: 6s;
}
div:nth-of-type(4) {
animation-name: cyan;
animation-delay: 9s;
}
div:nth-of-type(5) {
animation-name: blue;
animation-delay: 12s;
}
div:nth-of-type(6) {
animation-name: violet;
animation-delay: 15s;
}
@keyframes orange {
to { background-color: orange; }
}
@keyframes yellow {
to { background-color: yellow; }
}
@keyframes green {
to { background-color: green; }
}
@keyframes cyan {
to { background-color: cyan; }
}
@keyframes blue {
to { background-color: blue; }
}
@keyframes violet {
to { background-color: violet; }
}
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
But if you want to combine both together, it's also all possible:
div {
/* same for all */
width: 60px;
height: 60px;
display: inline-block;
background-color: white;
animation-fill-mode: forwards;
animation-duration: 3s;
}
div:nth-of-type(1) {
animation-name: orange, yellow, green, cyan, blue, violet;
animation-delay: 0s, 3s, 6s, 9s, 12s, 15s;
}
div:nth-of-type(2) {
animation-name: yellow, green, cyan, blue, violet;
animation-delay: 3s, 6s, 9s, 12s, 15s;
}
div:nth-of-type(3) {
animation-name: green, cyan, blue, violet;
animation-delay: 6s, 9s, 12s, 15s;
}
div:nth-of-type(4) {
animation-name: cyan, blue, violet;
animation-delay: 9s, 12s, 15s;
}
div:nth-of-type(5) {
animation-name: blue, violet;
animation-delay: 12s, 15s;
}
div:nth-of-type(6) {
animation-name: violet;
animation-delay: 15s;
}
@keyframes orange {
to { background-color: orange; }
}
@keyframes yellow {
to { background-color: yellow; }
}
@keyframes green {
to { background-color: green; }
}
@keyframes cyan {
to { background-color: cyan; }
}
@keyframes blue {
to { background-color: blue; }
}
@keyframes violet {
to { background-color: violet; }
}
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
Not at the moment. The documentation explicitly says that you can only use percentages:
https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes
Presumably, the reason behind it is that the duration of the animation isn't defined in the keyframes but in the animation-duration
property, so the interpolator must be able to stretch the keyframes to any duration.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With