Animaciones con CSS

publicado en la categoría CSS
Una animación con CSS es algo similar a una transición que se repite un número de veces y requiere de dos partes, establecer los intervalos y propiedades a modificar en @keyframes y la propiedad animation en cualquier etiqueta.

Las transiciones son la forma de cambiar una o varias propiedades de una etiqueta con un efecto visual tal que ese cambio no se realiza de manera instantánea sino que demora un cierto tiempo y por lo tanto, parece estar animado. Una animación con CSS es algo similar que requiere de dos partes, primero establecer los datos de esa animación y luego, agregar las propiedades correspondientes en la etiqueta.

Para crear una animación se utiliza la regla @keyframes donde se irán enumerando los pasos intermedios que existirán entre el inicio y el final. Esa regla debe tener un nombre que puede ser cualquiera pero irrepetible:

@keyframes NOMBRE {
	0% { /* las reglas iniciales */ }
	50% { /* las reglas al llegar a la mitad */ }
	100% { /* las reglas finales */ }
}

Una vez que tenemos definidas las reglas, nos falta agregar la propiedad animation en el elemento. Esta propiedad es una forma resumida de agregar varias propiedades juntas, algunas de las cuales son obligatorias y otras optativas:

animation: name duration timing delay iteration direction fill play;

animation-name es el nombre del keyframe que asociamos
animation-duration es el tiempo que durará esa animación
animation-timing-function define el modo en que se ejecutará ese cambio y los valores son los mismos que se usan en transition-timing-function
animation-delay es opcional y establece el tiempo para que comience la animación y por defecto es cero
animation-iteration-count es la cantidad de veces que se ejecutará (por defecto 1) pero podemos usar la palabra infinite para que se repita indefinidamente
animation-direction indica como se repetirá la animación: normal lo hará secuencialmente (es el modo por defecto); alternate lo hará de modo alternado (normalmente en los intervalos impares y inversamente en los pares); reverse lo hará en sentido inverso y alternate-reverse lo hará de modo inverso en los intervalos impares y normalmente en los pares
animation-fill-mode indica el estilo del elemento cuando no se está animando o la animación ha terminado; por defecto su valor es none pero admite otros valores: forwards especifica que al terminar, el elemento quedará con las propiedades definidas en el último intervalo; backwards especifica que al terminar, el elemento quedará con las propiedades definidas en el primer intervalo y both utilizará ambas
animation-play-state indica si la animación se ejecuta (running) o esta pausada (paused)

Las animaciones parecen engorrosas porque son algo engorrosas pero de nada sirve quejarse, es lo que hay ... y vale la pena animarse y experimentar con ellas.

Empecemos con un ejemplo sencillo y aprovechemos que el valor de 0% puede ser reemplazado por la palabra from y el de 100% por la palabra to:

@keyframes recrojo {
	from {
		background-color:#fff;
	}
	to {
		background-color:#f00;
	}
}
.demo {
	animation-name: recrojo;
	animation-duration: 1s;
	animation-iteration-count: infinite;
	animation-direction: alternate;
	/* animation: recrojo 1s infinite alternate; */
	background-color: #fff;
	border: 5px solid #ccc
	height: 100px;
	width: 200px;
}

Como se ve, puesta de ese modo, la animación es permanente y puede ser todo lo compleja que se quiera aunque también es posible colocarla en el evento hover y de esa manera sólo es lanzada cuando colocamos el cursor encima:

@keyframes recimg {
	0% {
		background-color: #f0ffff;
		background-position: 0% 50%;
		background-size: 0 0;
		font-size: 0em;
	}
	50% {
		background-color: #d0dddd;
	}
	100% {
		background-color: #fff;
		background-position: right 50%;
		background-size: 136px 200px;
		font-size:3em;
	}
}
.rectanguloimagen {
	background: #f0ffff url(http://i.imgur.com/viKMNl9.jpg) no-repeat scroll 50% 50%;
	background-size: 0 0;
	font-size: 0em;
	height: 200px;
	line-height: 200px;
	width: 450px;
}
.rectanguloimagen:hover {
	animation-direction: normal;
	animation-duration: 2s;
	animation-iteration-count: 1;
	animation-name: recimg;
	animation-fill-mode: forwards;
}
the beatles

Las animaciones CSS se pueden asociar a tres eventos de JavaScript:

animationstart se ejecuta cuando la animación comienza
animationiteration se ejecuta cuando la animación se repite
animationend se ejecuta cuando la animación se ha completado

En este ejemplo, al hacer click en el contenedor comienza la animación y cada vez que se repite, cambia de color:

click
ver/ocultar código ejemplo
<style>
	#rectangulomove {
		background: white;
		height: 100px;
		left: 5%;
		line-height: 100px;
		position: relative;
		width: 100px;
	}
	#rectangulomove.efecto {
		animation: 4s linear 0s alternate none infinite running recmove;
	}
	@keyframes recmove {
		from {left: 5%;}
		to {left: 85%;}
	}
</style>

<div class="demo rec">
	<div id="rectangulomove" onclick="iniciar()">click</div>
</div>

<script>
	var elDIV = document.getElementById("rectangulomove");
	elDIV.addEventListener("animationstart", iniciar);
	elDIV.addEventListener("animationiteration", repetir);
	elDIV.addEventListener("animationend", terminar);
	function iniciar() {
		 // iniciamos la animación y eliminamos el texto
		elDIV.className = "efecto";
		elDIV.innerText = "";
	}
	function repetir() {
		// permutar colores cada vez que se ejecuta
		if(elDIV.style.backgroundColor=="yellow"){
			elDIV.style.backgroundColor = "white";
		} else {
			elDIV.style.backgroundColor = "yellow";
		}
	}
	function terminar() {
		// como la animación es infinita nunca termina y este evento jamás se ejecuta
	}
</script>

De aquí en más, no queda más remedio que salir a investigar un poco.

ver/ocultar código ejemplo
<style>
@keyframes fade {
	0% {opacity:0;}
	10% {opacity:1;}
	100% {opacity:0;}
}
@keyframes fall {
	0% {top:10px;}
	100% {top:290px;}
}
@keyframes accumulate {
	0% {height:0px; opacity:0}
	100% {height:10px; opacity:75;}
}
@keyframes spin {
	0% {transform: rotate(-180deg) translate(0px, 0px);}
	100% {transform: rotate(180deg) translate(10px, 75px);}
}
#container{
	height: 300px;	position: relative;
	width: 350px;
}
#snow div {
	position: absolute;
	top: -40px;	animation-name: fall, fade, spin;
	animation-iteration-count: infinite;
	animation-direction: normal;
	animation-timing-function: ease-in;
	animation-name: fall, fade, spin;
	animation-iteration-count: infinite;
	animation-direction: normal;
	animation-timing-function: ease-in;
}
.snowflake {
	color: #fff;
	position: absolute;
}
.snowflake.f1 {font-size: 24px; left: 10px; animation-duration: 5s;}
.snowflake.f2 {font-size: 48px; left: 290px; animation-duration: 7s;}
.snowflake.f3 {font-size: 20px; left: 120px; animation-duration: 6s;}
.snowflake.f4 {font-size: 32px; left: 160px; animation-duration: 4s;}
</style>

<div id="container">
	<div id="snow" class="snow">
		<div class="snowflake f1">❅</div>
		<div class="snowflake f2">❄</div>
		<div class="snowflake f3">❅</div>
		<div class="snowflake f4">❄</div>
	</div>
</div>