Fundamentals of CSS Animation
Creating Shapes Using divs
You can create shapes in html and css by creating empty div elements and assigning them widith height and background-color css properties.
HTML:
<div id="squareDiv"></div>
CSS:
#squareDiv{ width: 100px; height: 100px; background-color: red; }
We can also turn this square div in to a circle, or circle-like shape by giving it a css property called border-radius. border-radius takes in a numerical value as input and creates a circular edge around the four corners of the div element by using the numerical input as the radius of the circle.
For example, if we add
border-radius: 10px;
to the code we already have from above:
We can also give the size of border-radius in percentages, relative to the size of the div element. So if I give 50% as my border-radius, this means that it will be 50% of my width and height of my div, which will end up being 50px and ultimately create a circle.
If your width and height values are not the same, by setting border-radius to 50%, you will create an ellipse:
You can also play around with the border elements of css to create outlines of shapes. In order to visualize the border around your div, you need to set your border-style. The default value of border-style is set to none, so you will need to over ride this by giving values such as solid, dotted, dashed and double. Use border-width to set the thickness of your border, and assign the color of your border with border-color.
#outlineDiv{ width: 100px; height: 100px; border-style: solid; /* other options: dashed, dotted, double... */ border-color: red; border-width: 10px; }
You can also assign different styles, colors and widths for the top, bottom, left and right borders.
#outlineDiv{ width: 100px; height: 100px; border-top-style: dashed; border-top-color: blue; border-top-width: 10px; border-bottom-style: dotted; border-bottom-color: red; border-bottom-width: 5px; border-left-style: double; border-left-color: green; border-left-width: 20px; border-right-style: solid; border-right-color: yellow; border-right-width: 30px; }
You can actually create triangle shapes using borders as well: by assigning no width and height to the div and making all but one borders transparent.
#outlineDiv{ width: 0px; height: 0px; border-bottom: 100px solid red; border-left: 100px solid transparent; }
The most important part of this "css trick" is that you can "transparent" as your color value. Another thing to note is that you can merge border-bottom-width, border-bottom-style and border-bottom-color into a single line of css, by just referring to border-bottom, and separating the values for width, style and color with a space.
You can create different triangle shapes, depending on which borders you make transparent.
Understanding Keyframes
We use @keyframes css attribute to define the rules of a particular animation. The syntax of the @keyframes tag is as follows:
@keyframes animationname {keyframes-selector {css-styles;}}
So, if we wanted to define an animation called "moveToRight" then, we write:
@keyframes moveToRight {keyframes-selector {css-styles;}}
CSS animation is simple. We are simply applying different css styles to a html element at different times. keyframes-selector is what defines the timing of when a particular css-style is applied to the html element.
Timing with Keyframes selectors
keyframes-selector can be values from and to or it can also be written in percentages. For example, in the case of this example code below:
@keyframes moveToRight { from{left: 0px;} to{left: 300px;} }
If the above @keyframes code is applied to a html element, it will move 300px to the right. This means that if the duration of the animation is 5 seconds (we will learn how to set the duration of an animation in a bit), at 0 second, the position of the html element will be at left: 0px; and at 5 second, the position will be at left: 300px;. Below is what happens if the above animation is applied(and told to repeat infinitely - which we will also learn how to do soon).
Using from and to keyframe-selectors, however, limits an animation to be a one-step action: it goes from one state to another. If we use percentages instead, we can put more steps in within the animation.
@keyframes moveToRight2 { 0%{left: 0px;} 25%{left: 250px;} 50%{left: 100px;} 100%{left: 300px;} }
Now, we've broken up the 5 second duration of the animation in 4 steps. At 0 second, the position is at left: 0px;, at 1.25 second, the position is at left: 250px;, at 2.5 second it is at left: 100px; and finally at 5 second, it is at left: 300px;. See this animation applied below.
So, the from keyframes-selector is same as 0%, and to is same as 100%.
Understanding Animation Properties
Now that we know how to define an animation using @keyframes, let's see how we can apply this animation to an html element.
Let's create an empty div and give it width, height and background-color so we see it. Don't forget to give it some sort of id so we can refer to it in css.
HTML:
<div id="changeColor"></div>
CSS:
#changeColor{ width: 100px; height: 100px; background-color: red; }
For practice, let's define a css animation that changes the background color from red to blue.
@keyframes redToBlue{ to{background-color: blue;} }
Note that I didn't define from. If from is not defined, it will use the css styles that is defined with the html element. In this cass, the from state will be background-color: red;.
animation-name
The way that we reference a @keyframe animation to a html element is by defining the animation name in the style. See the code below:
#changeColor{ width: 100px; height: 100px; background-color: red; animation-name: redToBlue; }
Now, the div with id changeColor will use @keyframes with name redToBlue. However, this code won't do anything, because we haven't give it how long the duration of the animation is supposed to be.
animation-duration
Again, like we did with passing animation-name, we define the duration of the animation in the style of the html element, like below:
#changeColor{ width: 100px; height: 100px; background-color: red; animation-name: redToBlue; animation-duration: 3s; }
The duration of the animation is measured in seconds - hense the "s" after the 3 as the argument for the animation-duration attribute. In this example, this means that it will take 3 seconds for the color to change from red to blue.
You might be saying "This is not working!" if you have been reading the instructions from top to here. If you refresh this page and come down to this section of code, you will see the animation. This is because we haven't told it to run how many times - so by default, the animation only runs once.
animation-iteration-count
Now, let's offset the default state of the animation running once, by defining the animation-iteration-count css attribute.
#changeColor{ width: 100px; height: 100px; background-color: red; animation-name: redToBlue; animation-duration: 3s; animation-iteration-count: 5; }
The argument of the animation-iteration-count attribute signifies the number of times the particular @keyframes animation will run. In this case, it will run for 5 times and then it will go back to the original state of background-color:red; and remain this way. There is one non-numeric value you can give to this attribute and it is "infinite".
animation-iteration-count: infinite;
Now this animation will run infinite times, as you see below.
animation-delay
This is a simple animation attribute that lets you have a delay at the beginning of your animation. Same as the animation-duration attribute, it is measured in seconds. Note that this delay will only happen at the very beginning of the animation - and not at the start of following iterations. The following code will put 5 second delay at the start of the animation.
animation-delay: 5s;
animation-fill-mode
This attribute can be important when animating a html element only once. This determines the end state of an animation. The default value of animation-fill-mode attribute is none, meaning that it will return to the original style that the html is applied with.
Let's create an empty square div with original background-color: red;.
#changeColors{ width: 100px; height: 100px; background-color: red; animation-name: blueToGreen; animation-duration: 5s; }
In our @keyframes, lets set the starting background color at from as background-color: blue; and at to as background-color: green;.
@keyframes blueToGreen{ from{background-color: blue;} to{background-color: green;} }
default (none) example
forwards example
The two examples above are using default animation-iteration-count (meaning it will only run once), so it may not be animating when you look at this right now. The top example is the default example - when animation-fill-mode attribute is not called. You will see that it's changed back to the original style applied to this div, which was at background-color: red; The bottom one:
animation-fill-mode: forwards;remains at background-color: green;, because we told it to remain forwards, as in "change the css style to what it is at the end of the animation".
animation-direction
This attribute lets you decide whether you want to run the sequence of defined @keyframes animation in a normal order, reverse order or alternate order. To see the differences, we are going to apply the same @keyframes animation and give it different values for the animation-direction property.
default (normal) example
reverse example
alternate example
The top example is when no animation-direction property is given, so using the default normal order of animation. The middle example uses:
animation-direction: reverse;You will see that this example goes from right to left, not left to right as it is in the first example. The bottom example uses:
animation-direction: alternate;which alternates between going from left to right and right to left.
animation-timing-function
So far, the animations defined change from one state to another in a linear way, meaning that the change happens with a fixed constant speed which is dependant on animation-duration and the actions defined in the @keyframes. animation-timing-function lets you set the speed curve of your animation. For more detailed explanation of this property, please visit the w3schools link. The link also contains all possible values you can give for the animation-timing-function attribute.
In this tutorial, we are going to look at ease-in-out and steps.
Let's reuse our first example of moving the empty div box from left to right by 300px and add animation-timing-function attribute and give it value "ease-in-out".
#moveToRight{ position: relative; width: 100px; height: 100px; background-color: red; animation-name: moveToRight; animation-duration: 5s; animation-iteration-count: infinite; animation-timing-function: ease-in-out; }
ease-in-out example
default (linear) example
For ease of comparison, the top one is the ease-in-out example and the bottom one is the exact same example as the first one we made in this tutorial - the default linear one. Can you see the difference? ease-in-out makes the speed of the animation "curved", meaning that it builds up to full speed slowly, then stops gradualy. Both animations, however, take exactly same time to finish: 5 seconds.
Now let's look at the steps() function that can be used to pass in as a value for the animation-timing-function attribute. The syntax for the steps value is as follows:
steps(int, start | end);
The first argument int is required, and indicates number of steps the animation will be broken up into. This number has to be greater than zero. The second argument is optional, and decides whether the step count will increase at the beginning of the action or the end of the action. This can create subtle difference in the way an html element is animated.
steps(5) example
steps(50) example
default (linear) example
The top one uses
animation-timing-function: steps(5);while the middle one uses
animation-timing-function: steps(50);and the bottom one is the first linear speed example placed here for comparison. The top example breaks up the movement in 5 steps, while the middle one does it in 50 steps. You will see that the top one doesn't actually reach all the way to the top. This is because the default value of the second optional value that we didn't pass in for this example is end. Let's change this default value and give a second argument to our animation-timing-function:
animation-timing-function: steps(5, start);
Example | Typing Animation
As a practice, we are going to use a combination of things we learned above to create a "typing" animation. This is what we are going to acheive:
This is being typed!!! |
Using @keyframes and css animation properties, we can create this typing effect, with the blinking cursor as a plus.
The trick to this animation is, in reality, it is only manipulating the width of the paragraph html element that can be seen on the browser. Let's create a paragraph tag with the id "type" and put some sort of text inside. Let's also put a span tag with id "blink" inside the paragraph tag and put "|" (pipleline character) inside, which we are going to animate to be our blinking cursor.
<p id="type">This is a sentence!<span id="blink"> |</p></p>Next, we are going to define our @keyframes for the typing animation and the blinking cursor animation:
@keyframes type{ from{width: 0px;} } @keyframes blink{ from{opacity: 0;} }You might be asking - is this all it is? Yes! The typing function is just changing the width of the paragraph tag from 0px to a certain width and the blinking animation is simply changing the opacity from 0% to 100%. Now let's apply these animations to our html elements.
#type{ animation-name: type; animation-duration: 5s; animation-iteration-count: infinite; } #blink{ animation-name: blink; animation-duration: 1s; animation-iteration-count: infinite; }
This is a sentence! |
THIS IS NOT HOW IT IS SUPPOSED TO LOOK LIKE! Well, it's because, we are not done! The blinking cursor seems to work fine, but it is the type animation that doesn't look like how it is supposed to yet. The first thing that may come to your mind is, because I said that all this animation does is changing the width from 0 to a certain width, we should maybe try to define the width. Let's add the width to be 150px - so now the style of my type paragraph is:
#type{ width: 150px; animation-name: type; animation-duration: 5s; animation-iteration-count: infinite; }
This is a sentence! |
Okay, so it looks a little closer to what we want. I wish if there was a way of hiding everything else except for the top part of the animation! Well, there is a way. First, lets tell it to hide the overflow of the content of the paragraph.
#type{ /* let's hide the overflow content!*/ overflow: hidden; width: 150px; animation-name: type; animation-duration: 5s; animation-iteration-count: infinite; }
This is a sentence! |
This is a little more fluid than the last version, but we need to add another css style to this to make it even more so. We need to tell the white-spaces of this sentence (meaning the spacebar characters in between the words) to not wrap at the bottom.
#type{ /* do not wrap the white-spaces at the bottom!*/ white-space: nowrap; overflow: hidden; width: 150px; animation-name: type; animation-duration: 5s; animation-iteration-count: infinite; }
This is a sentence! |
Now, the animation is not multi-lined! However, the difference between the end product that I showed at the beginning compared to this one is that, it's too fluid. We need to create a choppy movement that make it look like its being typed. This is where the animation-timing-function comes in. We are going to use thes steps value and give it 40 steps.
#type{ white-space: nowrap; overflow: hidden; width: 150px; animation-name: type; animation-duration: 5s; animation-iteration-count: infinite; /* make choppy type-like movement! */ animation-timing-function: steps(40); }
This is a sentence! |
And we are done! The w3schools link on css animation properties will have more in-depth description about each of those described in this tutorial!
Code from Workshop
HTML:
<!DOCTYPE html> <html> <head> <title></title> <link rel="stylesheet" type="text/css" href="css/style.css"> </head> <body> <div class="square"></div> <div class="circle"></div> <div class="ellipse"></div> <div class="triangle"></div> </body> </html>
CSS:
.square{ height: 200px; background-color: red; width: 200px; animation-name: rotateAround; animation-duration: 5s; animation-iteration-count: infinite; animation-direction: alternate; } .circle{ height: 200px; background-color: blue; width: 200px; border-radius: 50%; } .ellipse{ height: 100px; background-color: green; width: 200px; border-radius: 50%; } .triangle{ height: 0; /* background-color: yellow; */ width: 0; border-style: solid; border-width: 150px; border-top-color: red; border-bottom-color: transparent; border-left-color: transparent; border-right-color: red; animation-name: changeBG; animation-duration: 2s; animation-iteration-count: 1; animation-fill-mode: forwards; animation-delay: 0s; animation-direction: alternate; animation-timing-function: steps(10); } @keyframes changeBG{ 0%{ border-top-color: green; border-right-color: green; margin-left: 0px; border-width: 50px; } 50%{ border-width: 300px; } 100%{ border-top-color: blue; border-right-color: yellow; margin-left: 150px; border-width: 150px; } } @keyframes rotateAround{ 0%{ background-color: red; transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg) scaleX(0.5); } 50%{ background-color: green; transform: rotateX(120deg) rotateY(230deg) rotateZ(30deg) scaleX(5.0) scaleY(0.5); } 100%{ background-color: pink; transform: rotateX(0deg) rotateY(80deg) rotateZ(300deg) scaleX(0.1) scaleY(10); } }