Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expressing CSS3 @keyframes using seconds instead of percentages

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?


Example using Multiple Elements

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>
like image 849
Rounin - Glory to UKRAINE Avatar asked Mar 28 '18 22:03

Rounin - Glory to UKRAINE


2 Answers

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>

Regarding question's edit

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>
like image 147
Kaiido Avatar answered Oct 20 '22 01:10

Kaiido


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.

like image 43
Máté Safranka Avatar answered Oct 20 '22 00:10

Máté Safranka