Home>

I learned CSS3 syntax@keyframesin January 2016, and more than 2 years later, I found myself using @keyframes animations for much of my work (more complex thantransitionsCSS3, and less cumbersome than javascript based animations).

One thing I'm sorely missing is the ability to express @keyframes in seconds rather than percentages. Are there any hacks for doing this?

I know I can use the following trick for 100 seconds to cycle through the 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 that means the animation is still running (albeit invisibly) for an additional 82 seconds after (efficient) completion. Among other things, this makes it impossible to perform multiple iterations.

Actually I would like to write 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 a better approach than the one I detailed in the code box above?


Adding to the original conditions in the question:

An example of using multiple elements

In hindsight, I realize that I probably made the above example too simple given that it involves animating a single element, and my question initially arises from a desire to animate multiple elements in sync with each other.

So, here's a slightly more complex example showing a setup much closer to the one that spawned 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 >

Free translation of the question Expressing CSS3 @keyframes using seconds instead of percentagesfrom the participant @Rounin.

  • Answer # 1

    Remember that you can run multiple animations for the same element, and that you can independently set their duration, delay, and all other animation rules.

    For example, you can split all your keyframes into separate @keyframes rules. Then it is easy to control when they take action and to link them into chains.

    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 >
    

    Additions caused by editing the question

    In this case, you don't even need to combine multiple animations in one element, but just set the appropriate animation delay:

    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, this is also 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 >
    

    Free translation the answerfrom the participant @Kaiido.

  • Answer # 2

    Remember that you can run multiple animations for the same element, and that you can independently set their duration, delay, and all other animation rules.

    For example, you can split all your keyframes into separate @keyframes rules. Then it is easy to control when they take action and to link them into chains.

    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 >
    

    Additions caused by editing the question

    In this case, you don't even need to combine multiple animations in one element, but just set the appropriate animation delay:

    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, this is also 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 >
    

    Free translation the answerfrom the participant @Kaiido.