Hackernoon logoHow To Create an Animation with CSS by@LoboArcano

How To Create an Animation with CSS

image
Roberto Perez Hacker Noon profile picture

@LoboArcanoRoberto Perez

Many times animations are implemented on a web page to improve the user experience, making it more attractive and intuitive. With the animation property and the @keyframes rule, you can create any animation you have in mind by manipulating a large number of properties. This article shows the basics of making animations using a small project as an example, consisting of four squares jumping into four other squares as they move to the right and end up stacked in a tower.

Before starting with the animations we need to create a container in the index.html file, which we will call canvas, this will be the place where all the animations will occur. Also, we will create static squares and those that will be in motion.

index.html

<div class="canvas"> 
  <div class="static-square"></div> 
  <div class="static-square"></div> 
  <div class="static-square"></div>
  <div class="static-square"></div> 
  <div class="animated-square"></div> 
  <div class="animated-square"></div> 
  <div class="animated-square"></div> 
  <div class="animated-square"></div> 
</div> 

Our canvas will have a relative position and the rest of the elements will have an absolute position, that way we can easily manipulate them and place them in the desired place.

It is important that the canvas has an overflow property with the value hidden so that no element is displayed outside the canvas. And the static squares will be at the bottom of the canvas with bottom: 0 and we will distribute them along with the canvas by the left property.

style.css

.canvas { 
  overflow: hidden; 
  position: relative; 
  height: 500px; 
  width: 1000px; 
  background: black; 
  margin: 15px auto 0; 
} 

.canvas .static-square { 
  position: absolute; 
  bottom: 0; 
  height: 100px; 
  width: 100px; 
  background-color: rgb(251, 255, 0); 
} 

.canvas .static-square:nth-child(1) { 
  left: 100px; 
} 

.canvas .static-square:nth-child(2) { 
  left: 300px; 
} 

.canvas .static-square:nth-child(3) { 
  left: 500px; 
} 

.canvas .static-square:nth-child(4) { 
  left: 700px; 
} 

Now it's time to start the animations. All animated squares will appear from the top left of the canvas just 100px outside the canvas waiting for their turn to appear on the scene, then they will start jumping over the static squares. To achieve this we will use different properties to accomplish the animation.

Each animation needs a name, with animation-name we can name our animation, in this case, we will call it "bounce". We also need to determine the length of time the animation will last with animation-duration; since we are going to see this animation several times we will keep a short duration of 4 seconds. With animation-timing-function we can decide the speed curve, there are several different speeds so we will use a different one for each square. In this example, you will see the different speed curves https://www.w3schools.com/css/tryit.asp?filename=trycss3_animation_speed.

This would be enough to start working on animation, but there would be several problems. The first of them is that when the animation ends, the square will return to its initial position; to avoid this we will use animation-fill-mode: forwards, in this way the square will maintain the final position of the animation.

The next problem is that the animations of the four squares started at the same time, so we will be adding a second delay from the animation of the second square with animation-delay: 1s.

style.css

.canvas .animated-square { 
  position: absolute; 
  top: 50px; 
  left: -100px; 
  height: 100px; 
  width: 100px; 
} 

.canvas .animated-square:nth-child(5) { 
  background-color: rgb(255, 0, 0); 
  animation-name: bounce; 
  animation-duration: 4s; 
  animation-delay: 0s; 
  animation-timing-function: linear; 
  animation-fill-mode: forwards; 
} 

.canvas .animated-square:nth-child(6) { 
  background-color: rgb(4, 0, 255); 
  animation-name: bounce; 
  animation-duration: 4s; 
  animation-delay: 1s; 
  animation-timing-function: ease; 
  animation-fill-mode: forwards; 
} 

.canvas .animated-square:nth-child(7) { 
  background-color: rgb(0, 228, 11); 
  animation-name: bounce; 
  animation-duration: 4s; 
  animation-delay: 2s; 
  animation-timing-function: ease-in; 
  animation-fill-mode: forwards; 
} 

.canvas .animated-square:nth-child(8) { 
  background-color: rgb(0, 171, 214); 
  animation-name: bounce; 
  animation-duration: 4s; 
  animation-delay: 3s; 
  animation-timing-function: ease-in-out; 
  animation-fill-mode: forwards; 
}

Perfect!

Now we can start the animation. It is here when we need the @keyframes rule where we can give the animation instructions in a range from 0% to 100%. In this range, we will change the values of top and left to move the squares up and down as they move to the right until they occupy their final position to form a stack.

And to give it a little more life we will use the transform property and the rotate function to which we will add 180 degrees of rotation in each step.

One second, how will we know the perfect time to give the instructions? Well, for the bounce animation we have 8 key points, the squares will move 4 times down and 4 times up; so we will divide 100 by 8 and the result is 12.5. Therefore the first set of instructions will be 12.5%, the second 25%, and so on.

style.css

@keyframes bounce { 
  12.5% { 
    left: 100px; 
    top: 320px; 
    transform: rotate(180deg); 
  } 
 
  25% { 
    left: 200px; 
    top: 50px; 
    transform: rotate(360deg); 
  } 
 
  37.5% { 
    left: 300px; 
    top: 320px; 
    transform: rotate(540deg); 
  } 

  50% { 
    left: 400px; 
    top: 50px; 
    transform: rotate(720deg); 
  } 

  62.5% { 
    left: 500px; 
    top: 320px; 
    transform: rotate(900deg); 
  } 
 
  75% { 
    left: 600px; 
    top: 50px; 
    transform: rotate(1080deg); 
  } 

  87.5% { 
    left: 700px; 
    top: 320px; 
    transform: rotate(1260deg); 
  } 

  100% { 
    left: 800px; 
    top: 50px; 
    transform: rotate(1440deg); 
  } 
}

Now we need to add a second animation to move the squares to their final position. To do this we must return to the properties of the first animation and separate the values of the second animation with a comma. Since each square will occupy a different position, we will need 4 animations, which we will call final, final2, final3, and final4.

In order for the second animation to start right after the first animation, it is necessary to add a time delay equivalent to the duration of the first animation and its delay, if any. The value of animation-duration will be one second.

Since we have 4 animations we also need 4 @keyframes and we will only give the instructions so that the squares occupy their final position to form the tower.

style.css

.canvas .animated-square:nth-child(5) { 
  background-color: rgb(255, 0, 0); 
  animation-name: bounce, final; 
  animation-duration: 4s, 1s; 
  animation-delay: 0s, 4s; 
  animation-timing-function: linear; 
  animation-fill-mode: forwards; 
} 

.canvas .animated-square:nth-child(6) { 
  background-color: rgb(4, 0, 255); 
  animation-name: bounce, final2; 
  animation-duration: 4s, 1s; 
  animation-delay: 1s, 5s; 
  animation-timing-function: ease; 
  animation-fill-mode: forwards; 
} 

.canvas .animated-square:nth-child(7) { 
  background-color: rgb(0, 228, 11); 
  animation-name: bounce, final3; 
  animation-duration: 4s, 1s; 
  animation-delay: 2s, 6s; 
  animation-timing-function: ease-in; 
  animation-fill-mode: forwards; 
} 

.canvas .animated-square:nth-child(8) { 
  background-color: rgb(0, 171, 214); 
  animation-name: bounce, final4; 
  animation-duration: 4s, 1s; 
  animation-delay: 3s, 7s; 
  animation-timing-function: ease-in-out; 
  animation-fill-mode: forwards; 
} 

@keyframes final { 
  0% { 
    left: 800px; 
    top: 50px; 
    transform: rotate(1440deg); 
  } 
 
  40% { 
    left: 900px; 
    top: 300px; 
    transform: rotate(1530deg); 
  } 
 
  80% { 
    left: 900px; 
    top: 400px; 
    transform: rotate(1440deg); 
  } 
 
  100% { 
    left: 900px; 
    top: 400px; 
    transform: rotate(1440deg); 
  } 
} 

@keyframes final2 { 
  0% { 
    left: 800px; 
    top: 50px; 
    transform: rotate(1440deg); 
  } 
 
  50% { 
    left: 900px; 
    top: 300px; 
    transform: rotate(1530deg); 
  } 

  100% { 
    left: 900px; 
    top: 300px; 
    transform: rotate(1530deg); 
  } 
} 

@keyframes final3 { 
  0% { 
    left: 800px; 
    top: 50px; 
    transform: rotate(1440deg); 
  } 
 
  40% { 
    left: 900px; 
    top: 200px; 
    transform: rotate(1530deg); 
  } 

  100% { 
    left: 900px; 
    top: 200px; 
    transform: rotate(1530deg); 
  } 
} 

@keyframes final4 { 
  0% { 
    left: 800px; 
    top: 50px; 
    transform: rotate(1440deg); 
  } 

  40% { 
    left: 900px; 
    top: 100px; 
    transform: rotate(1530deg); 
  } 
 
  100% { 
    left: 900px; 
    top: 100px; 
    transform: rotate(1530deg); 
  } 
}

As you can see 3 of the @keyframes have equal values for 50% and 100%, this is completely necessary to keep the animation flowing. With this we would finish the animation of the jumping squares; now how about we give a little life to static squares.

Let's do something simple, when the static square is hit by the animated square, we will reduce its height and increase its width, and then recover its original shape. This time we will use the animation shortcut to write everything on one line.

Then, the animation name will be "smash", with a duration of one second, the speed curve will be linear and the fill-mode will be forwards. Unlike past animations this time we will need the animation to repeat 4 times, for this we will use iteration-count to specify the number of iterations that the animation will have, in our case, it will be 4.

We can add a second animation in which the static square acquires the color of the animated square when they come into contact and finally recovers its color. We will call this animation "splash".

style.css

.canvas .static-square { 
  position: absolute; 
  bottom: 0; 
  height: 100px; 
  width: 100px; 
  background-color: rgb(251, 255, 0); 
  animation: 1s smash linear 4 forwards, 5s splash linear 1 forwards; 
}  
 
@keyframes smash { 
  49% { 
    height: 100px; 
    width: 100px; 
  } 

  50% { 
    height: 75px; 
    width: 125px; 
  }
 
  100% { 
    height: 100px; 
    width: 100px; 
  } 
} 

@keyframes splash { 
  9% { 
    background-color: rgb(251, 255, 0); 
  }  

  10% { 
    background-color: rgb(255, 0, 0); 
  } 

  29% { 
    background-color: rgb(255, 0, 0); 
  } 

  30% { 
    background-color: rgb(4, 0, 255); 
  } 

  49% { 
    background-color: rgb(4, 0, 255); 
  } 

  50% { 
    background-color: rgb(0, 228, 11); 
  } 

  69% { 
    background-color: rgb(0, 228, 11); 
  }

  70% { 
    background-color: rgb(0, 171, 214); 
  }  

  100% { 
    background-color: rgb(251, 255, 0); 
  } 
}

As you can see it is possible to manipulate the background-color in the animations, so now we are going to replicate the resource used in the old cartoons in which they repeated the background while the characters moved horizontally or vertically.

We will first create a new element in index.html with the top-bar class. The key to creating this effect is that the beginning of the background must be exactly the same as the end, to fulfill this purpose in a simple way we will use gradient-linear (you can also use an image that meets the previous condition). For this animation we must increase the background-size depending on the direction in which the background moves; in our animation, it will scroll vertically so we will increase the height of the background-size.

Regarding the properties of the animation, the name will be ''party-bar'', the duration of four seconds (changing this value you can change the speed of the animation), the speed curve will be linear and as in this occasion we want the animation to repeat indefinitely, we will use the infinite value for iteration-count.

The @keyframes is quite simple, you just have to change the vertical value of the background-position. Due to this simplicity, we are able to use the keywords "from" and "to" that are equal to 0% and 100% respectively.

index.html

<div class="canvas"> 
  <div class="static-square"></div> 
  <div class="static-square"></div> 
  <div class="static-square"></div> 
  <div class="static-square"></div> 
  <div class="animated-square"></div> 
  <div class="animated-square"></div> 
  <div class="animated-square"></div> 
  <div class="animated-square"></div> 
  <div class="top-bar"></div> 
</div> 

style.css

.top-bar { 
  position: absolute; 
  top: 0; 
  left: 0; 
  height: 70px; 
  width: 100%; 
  background: 
    linear-gradient( 
      0deg, 
      rgba(255, 0, 230, 1) 15%,
      rgba(23, 250, 255, 1) 40%, 
      rgba(0, 177, 238, 1) 65%, 
      rgba(255, 0, 230, 1) 85% 
  ); 
  background-size: 100% 1000%; 
  animation-name: party-bar; 
  animation-duration: 4s; 
  animation-timing-function: linear; 
  animation-iteration-count: infinite; 
} 

@keyframes party-bar { 
  from{ 
    background-position: 0% 0%; 
  } 
 
  to { 
    background-position: 0% 100%; 
  } 
} 

One last animation, I promise. This time we will create lights that turn on and off in the background and for this animation to work properly we have to change the background of the canvas to a radial-gradient, and we will see why.

This animation will be called ''light'', it will have a duration of two seconds, an ease-in-out speed curve, and of course, the iterations will be infinite.

Now that we have a radial background we can move the center of the background in the @keyframes as well as change its color.

style.css

.canvas { 
  overflow: hidden; 
  position: relative; 
  height: 500px; 
  width: 1000px; 
  background: 
    radial-gradient( 
      circle, 
      rgba(0, 0, 0, 1) 0%, 
      rgba(0, 0, 0, 1) 100% 
    ); 
  margin: 15px auto 0; 
  animation: 2s light ease-in-out infinite; 
} 
 
@keyframes light { 
  5% { 
    background: 
      radial-gradient( 
        circle,
        rgba(0, 0, 0, 1) 0%, 
        rgba(0, 0, 0, 1) 100%
     ); 
  } 
 
  10% { 
    background: 
      radial-gradient( 
        circle at 15% 30%, 
        rgba(242, 255, 23, 1) 0%,
        rgba(237, 238, 0, 1) 5%, 
        rgba(20, 20, 20, 1) 45%, 
        rgba(4, 4, 4, 1) 65% 
      ); 
  } 
 
  15% { 
    background: 
      radial-gradient( 
        circle, 
        rgba(0, 0, 0, 1) 0%, 
        rgba(0, 0, 0, 1) 100%
      ); 
  } 

  25% { 
    background: 
       radial-gradient( 
         circle, 
         rgba(0, 0, 0, 1) 0%,
         rgba(0, 0, 0, 1) 100% 
       ); 
  } 
 
  30% { 
    background: 
      radial-gradient( 
        circle at 85% 30%, 
        rgba(58, 214, 0, 1) 0%, 
        rgba(0, 185, 3, 1) 5%, 
        rgba(0, 0, 0, 1) 45%, 
        rgba(0, 0, 0, 1) 65% 
      ); 
  } 
 
  35% { 
    background: 
       radial-gradient( 
         circle, 
         rgba(0, 0, 0, 1) 0%, 
         rgba(0, 0, 0, 1) 100% 
       ); 
  } 
 
  45% { 
    background: 
       radial-gradient( 
         circle, 
         rgba(0, 0, 0, 1) 0%, 
         rgba(0, 0, 0, 1) 100% 
       ); 
  } 
 
  50% { 
    background: 
      radial-gradient( 
        circle at 15% 70%, 
        rgba(0, 160, 237, 1) 0%, 
        rgba(10, 99, 191, 1) 5%, 
        rgba(0, 0, 0, 1) 45%, 
        rgba(0, 0, 0, 1) 65% 
      ); 
  } 

  55% { 
    background: 
       radial-gradient( 
         circle, 
         rgba(0, 0, 0, 1) 0%, 
         rgba(0, 0, 0, 1) 100% 
       ); 
  } 
 
  65% { 
    background: 
       radial-gradient( 
         circle, 
         rgba(0, 0, 0, 1) 0%, 
         rgba(0, 0, 0, 1) 100% 
       ); 
  } 

  70% { 
    background: 
      radial-gradient( 
        circle at 85% 70%, 
        rgba(255, 0, 0, 1) 0%,
        rgba(224, 11, 11, 1) 5%, 
        rgba(3, 0, 0, 1) 45%, 
        rgba(0, 0, 0, 1) 65% 
      ); 
  } 

  75% {
    background: 
       radial-gradient( 
         circle, 
         rgba(0, 0, 0, 1) 0%, 
         rgba(0, 0, 0, 1) 100% 
       ); 
  }

  85% { 
    background: 
       radial-gradient( 
         circle, 
         rgba(0, 0, 0, 1) 0%,
         rgba(0, 0, 0, 1) 100% 
       ); 
  } 

  90% { 
    background: 
      radial-gradient( 
        circle at 50% 50%, 
        rgba(124, 0, 255, 1) 0%,
        rgba(102, 1, 190, 1) 15%, 
        rgba(0, 0, 0, 1) 55%, 
        rgba(0, 0, 0, 1) 100% 
      ); 
  } 

  95% { 
    background: 
       radial-gradient( 
         circle, 
         rgba(0, 0, 0, 1) 0%, 
         rgba(0, 0, 0, 1) 100% 
       ); 
  } 
} 

Now you know the basics to create animations! You can see the complete project here: https://codepen.io/LoboArcano/pen/eYNqRYJ.

Don't stop experimenting!

Tags

Join Hacker Noon

Create your free account to unlock your custom reading experience.