Over the last few years, designers have begun to use a lot of animations directly within HTML. That’s kind of cool, as you don’t need a plugin in order to see their work. There are several ways to make animations in HTML and in this article I will summarize a lot of examples and techniques for creating animations directly in HTML using both JavaScript and CSS.
JavaScript way
I spent several years in Flash development. To make an animation there, you have to create different static images that display in a sequence thereby creating the illusion of movement. The same approach is valid for HTML. For example, if you have five seconds and increase the width of a DOM element five times with 20px the result will be an animation.
One popular way to make animations is to use JavaScript. For example, you could create a function, which executes again and again and changing a property of a DOM element. For example, the below code adjusts the width of of an element in the context of a loop.
var width = 100;
var to = 200;
var loop = function() {
if(++width < to) {
element.style.width = width + "px";
setTimeout(loop, 1);
}
}
loop();
The result is something like this:
[iajsfiddle user=”krasimir” fiddle=”gvn9d/8″ height=”150px” width=”100%” show=”result,js,html,css” skin=”default”]
As far as I know, jQuery uses similar approach for its .animate
method.
For a good amount of time this was enough. It was a popular way to create animations in HTML. The good thing is that you have control over the whole process, knowing when the animation starts and when, exactly, it ends. You could easily decide to make something else occur in the middle of the animation or 20% before it finishes.
Easing
Of course, creating linear movements is not enough. That’s why we have ease functions, which are designed to change the values applied to the element in a manner to make the animation more interesting. In the world of Flash, Robert Penner made a big impact by introducing his easing methods. The same idea was later moved to JavaScript and today there is even a plugin for jQuery to handle easing.
So, how could we use easing? Let’s say that we want to change a div
‘s width from 0px to 10px in 10 steps. If we use linear movement the values, which we have to apply will look like this:
step 1 - 1px
step 2 - 2px
step 3 - 3px
step 4 - 4px
step 5 - 5px
step 6 - 6px
step 7 - 7px
step 8 - 8px
step 9 - 9px
step 10 - 10px
It’s simple math isn’t it? However, if we have a bit more complex values like, for example, from 232px to 306px in 14 steps we definitely need a helper function. It could be something like this:
var calcAnimation = function(from, to, steps) {
var diff = Math.abs(to - from);
var res = [];
var valuePerStep = diff / steps;
from += valuePerStep;
for(var i=0; i<steps; i++) {
res.push(from + (i * valuePerStep));
}
return res;
}
The function gets the initial value, target value and number of steps. It returns an array containing all the values that should be applied. For example:
calcAnimation(0, 10, 10) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
calcAnimation(0, 20, 5) // [4, 8, 12, 16, 20]
calcAnimation(-10, 10, 10) // [-8, -6, -4, -2, 0, 2, 4, 6, 8, 10]
The example above could be translated to the following version to perform the actual animation:
var animation = {from: 100, to: 200, steps: 50};
var values = calcAnimation(animation.from, animation.to, animation.steps);
var currentIndex = 0;
var loop = function() {
if(currentIndex < values.length) {
element.style.width = values[currentIndex] + "px";
currentIndex += 1;
setTimeout(loop, 1);
}
}
loop();
The calcAnimation
function creates a linear type of movement. It’s like that because we used the most simple calculation to create the values. Once we get the difference between the starting and ending point we divide it to the number of steps. The result is a number, which we have to apply to the property on every step. Luckily we are able to replace our simple calculation with a better function. For example:
var calcAnimationOutElastic = function(from, to, steps) {
var InOutElastic = function(t, b, c, d, a, p) {
if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
if (!a || a < Math.abs(c)) { a=c; var s = p/4; }
else s = p/(2*Math.PI) * Math.asin (c/a);
return (a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b);
}
var res = [];
for(var i=0; i<steps; i++) {
res.push(InOutElastic(i, from, to, steps, 0, 0));
}
return res;
}
The result is a more interesting, non-linear animation:
[iajsfiddle user=”krasimir” fiddle=”XCDzS/4″ height=”150px” width=”100%” show=”result,js,html,css” skin=”default”]
You don’t need to try to understand the math behind InOutElastic
method. You just need to know that it returns a set of values should be appled to create the animation.
CSS way
There are a lot of benchmarks showing that CSS3 animations are faster then their JavaScript equivalenta. For instance, here is a small experiment proving that. There are two ways to create animations with CSS: transitions and animations.
CSS transitions require two properties to be set –transition-property
and transition-duration
transition-property: background;
transition-duration: 500ms;
Please note that, in these examples, for the sake of simplicity I am not including the browser specific prefixes.
Here is an example. Because the transition properties are added, the background color is changed smoothly when you hover the button.
[iajsfiddle user=”krasimir” fiddle=”EcFQF/2″ height=”150px” width=”100%” show=”result,js,html,css” skin=”default”]
If you have several properties that need to be transitioned, you can split them with commas.
There is also CSS animation, which gives you ability to determine the values in different moments of the animation process, not only at the beginning and the end. A simple example might include changing the background color at specified points in the animation:
@keyframes 'bg-animation' {
0% { background: #C9C9C9; }
50% { background: #61BE50; }
100% { background: #C9C9C9; }
}
.star:hover {
animation-name: 'bg-animation';
animation-duration: 2s;
animation-iteration-count: infinite;
}
This would give you a button hover animation like the following:
[iajsfiddle user=”krasimir” fiddle=”fQqqY/2″ height=”150px” width=”100%” show=”result,js,html,css” skin=”default”]
While it is clear that CSS animations are better choice than JavaScript animation there are some disadvantages:
- You can’t stop or pause animations;
- The syntax is not so nice;
- It is a little bit difficult to sync different animations.s
The proper way
My opinion is that we should stick to CSS transitions for the simple hover or show/hide animations and use CSS animations for complex use cases. That’s because we are concerned about performance. If we decide to use only JavaScript then our job is kinda easy but the final result will may perform poorly, especially on the mobile devices.
Understanding how to start an animation
Normally you know how your final frame should look, so you can begin by creating anew CSS class containing the values for that final frame. After that, just add the class to the element to begin the animation and remove it when you want to return to the initial state. The adding of the class will automatically start the process.
var element = document.querySelector(".star");
element.addEventListener("mouseover", function() {
if(element.className.indexOf('star-hover') === -1) {
element.className += ' star-hover';
}
});
element.addEventListener("mouseout", function() {
element.className = element.className.replace(/ star-hover/g, '');
});
The following example uses the code above to add and remove classes on the button:
[iajsfiddle user=”krasimir” fiddle=”KpKgs/2″ height=”150px” width=”100%” show=”result,js,html,css” skin=”default”]
Catching the end of the animation
This is a critical part of creating complex animations. Every browser has its own name for the event that is fired, but the following code offers a cross-browser solution. A similar technique is used in Modernizr.
function whichTransitionEvent(el){
var t;
var transitions = {
'transition':'transitionend',
'OTransition':'oTransitionEnd',
'MozTransition':'transitionend',
'WebkitTransition':'webkitTransitionEnd'
}
for(t in transitions){
if( el.style[t] !== undefined ){
return transitions[t];
}
}
}
var transitionEnd = whichTransitionEvent(element);
element.addEventListener(transitionEnd, function(event) {
if(element.className.indexOf('star-expand') === -1) {
element.className += ' star-expand';
}
});
The following widget shows the code in action. If you click on the button you should see that, first, the color is changed and then the width of the box is increased. That’s because two new CSS classes are added sequentially, one after the other.
[iajsfiddle user=”krasimir” fiddle=”7rtCB/6″ height=”150px” width=”100%” show=”result,js,html,css” skin=”default”]
Keep in mind that the event handler receives an object which contains information about the animation like, for example, which property was changed, tje elapsed time and so on.
Be creative
I strongly recommend checking out Animate.css. It is a collection of CSS classes which you can useto apply some nice animations to DOM elements without needing to worry about the math.
[iajsfiddle user=”krasimir” fiddle=”uYrbA/7″ height=”150px” width=”100%” show=”result,js,html,css” skin=”default”]
In the above example I simply attach/remove two classes: rotateInDownLeft
and bounceOutRight
. I also used additional helper for detecting the end of the animation. Animate.css
uses CSS animations, not CSS transitions, so the method is a bit changed:
function whichAnimationEvent(el){
var a;
var animations = {
'animation': 'animationend',
'OAnimation': 'oAnimationEnd',
'MozAnimation': 'animationend',
'WebkitAnimation': 'webkitAnimationEnd'
}
for(a in animations){
if( el.style[a] !== undefined ){
return animations[a];
}
}
}
This collection of classes in Animate.css is actually pure CSS. In the official repository of the project Dan Eden gave a little hint:
You can do a whole bunch of other stuff with *Animate.css* when you combine it with jQuery or add your own CSS rules. Dynamically add animations using jQuery with ease:
$('#yourElement').addClass('animated bounceOutLeft');
Animate.js
These days I’m trying to avoid the usage of libraries like jQuery when they are not necessary. For example, here I need to select an element and change its class attribute. There are solutions for that which use simple JavaScript.
I used the Animate.css library in two projects and in both I needed a tight control of the animations from within the JavaScript portion of the application. That’s why I decided to write a simple JavaScript class on top of Animate.css
that gives control over the animations. It is available in my fork of the library here.
The initialization
Just include animate.js
in your HTML and do the following:
var el = document.querySelector(".your-element-class");
var controller = Animate(el);
Adding a class (i.e. starting animation)
controller
.add('animated')
.add('bounceOutLeft')
The add
method appends a CSS class to the className
property of the element. The function also accepts a second parameter which is a handler that will be called once the animation finishes.
controller.add("flipInY", function() {
alert("flipInY finishes");
});
Removing a class (i.e. returning to the initial state)
controller.remove('bounceOutLeft');
Normally when you use the Out
methods your element is hidden at the end. If you want to return it to the initial state, you can use the remove
method.
Catching the end of an animation
All the functions in the controller’s API return the API itself. This means that you can create a functional chain like for example:
controller
.add("rotateOutUpRight")
.end("rotateOutUpRight", function() {
alert("rotateOutUpRight");
});
You may have nested closures but to keep the code readable it is good to use the end
method. It accepts the name of a class and a handler that will be notified at the end of the animation.
Very often I needed to start a new animation once another finishes. Instead of doing that in a closure, I changed the end
method a bit. It also accepts a string as a second parameter, which is actually a new Animate.css
class.
controller
.add("flipInY")
.end("flipInY", 'rotateInDownLeft')
.end("rotateInDownLeft", 'bounceOutDown');
Removing all the added animation.css classes
Sometimes you will need to remove everything before you start adding new classes. The following method accomplishes this task:
controller.removeAll();
Running animations in sequence
controller.sequence('flip', 'flipInX', 'flipOutX', 'flipOutY', 'fadeIn', 'fadeInUp');
I think that this method is self-explanatory. Keep in mind that every animation class is removed before the new one is added.
It is worth noting that every handler in the JavaScript class is called within the context of the API. So, the this
keyword actually points to the API and you are able to write things like the following:
Animate(el).add("flipInY", function() {
this.removeAll().add("fadeInUp");
});
Here is an example showing my little controller that actually demonstrates many of the available animations.
[iajsfiddle user=”krasimir” fiddle=”56V6e/3″ height=”150px” width=”100%” show=”result,js,html,css” skin=”default”]
Where to go from here
Hopefully this article has provided you with some useful information about some of the available options for creating animation in HTML, CSS and JavaScript. If you’d like to learn more about Animate.css, you can check the GitHub site which also offers the ability to generate a custom build including only the animations your application requires.
This article was originally published at https://krasimirtsonev.com/blog/article/Introduction-to-animations-in-HTML-css3-transitions-keyframes
Great tutorial, will be great resource for a friend who is starting to get into development.
Nice article. I thought of a couple of things while reading that might help others…
If you’re doing Javascript based animation, you should look into requestAnimationFrame. It’s a special browser function that can be used to sync the timing of your animation with the repaint cycle of the browser. Here’s an article by Paul Irish about it.
https://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
If you want to do CSS based animation, I HIGHLY recommend Transit. The API is just like jQuery’s animate method, but it uses CSS transforms behind the scenes. It supports easing and callbacks as well.
https://ricostacruz.com/jquery.transit/
> My opinion is that we should stick to CSS transitions for the simple hover or show/hide animations and use CSS animations for complex use cases.
Are you for CSS either way or is this a mistake?