Mover las cosas con animaciones CSS
Chris David Mills. 25 de abril de 2012. Artículo original en inglés
Introducción
Tradicionalmente, la web era un lugar muy estático. Animace no era posible de ninguna manera cuerda hasta la llegada de JavaScript, los GIFs animados y Flash, momento en el que nos regocijamos y aplaudimos la gran cantidad resultante de 'saltar intro' y horribles animaciones molestas.
Estaba todo muy bien, pero seguía sin haber manera para que los no desarrolladores creasen animaciones con estándares abiertos. Puedes dar salida a todos los argumentos religiosos que desees sobre que la animación que pertenece a la capa de comportamiento, y no a la capa de presentación, pero creo que la animación definitivamente cae en el ámbito del diseño. Y ahora, con las transiciones y animaciones CSS3, se pueden animar los elementos de nuestro sitio web. ¡Diseño web basado en estándares con más diversión! Y más 'saltar intro', si lo prefieres…
Opera tiene soporte para transiciones desde hace mucho tiempo, y ya hemos escrito sobre ellos en CSS3 transitions and 2D transforms. Este artículo se centra en la otra manera de animar las cosas usando hojas de estilo: las animaciones CSS. A continuación daremos una introducción concreta incluyendo el estado de la especificación y el soporte en navegadores, las diferencias entre animaciones y transiciones, la sintaxis básica, y una lista de ejemplos.
¿Es una tecnología madura?
La especificación de animaciones CSS, propuesta y editada por Apple, se encuentra actualmente en estado de Borrador de Trabajo y se etiqueta como "Anticuado" en la página de trabajo actual del grupo de trabajo de CSS, así que podemos esperar ver algunos cambios menores antes de que finalice, pero el principio básico debería mantenerse.
En cualquier caso, ya se ha aplicado experimentalmente en Firefox (desde la versión 5), Chrome (desde la 4), Safari (desde la 4), IE (en la versión 10) y Opera desde la versión 12. Nótese el "experimentalmente": esto significa que es necesario utilizar los prefijos apropiados de proveedor para cada navegador.
Sintaxis básica
Las animaciones difieren de las transiciones en que las transiciones sólo se activan cuando se produce un cambio de estado (al poner el ratón sobre un elemento, por ejemplo), mientras que las animaciones se pueden activar independientemente de un cambio de estado, por lo general un período de tiempo después de cargar una página, o un evento a través de JavaScript. Además, una animación de transición siempre se produce en cualquiera de las propiedades que cambian sus valores cuando se produce un cambio de estado, mientras que una animación CSS puede animar valores de la propiedad, incluso si esas propiedades no se establecen en el estado por defecto del elemento que se está animando.
Definir una animación
Para configurar una animación, primero hay que definir algunos fotogramas clave, en un nuevo de reglas, de esta forma:
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
Aquí se nos dice que esta animación se llama "spin", y lo que hace es girar suavemente 360 grados el elemento al que se aplique. Ninguna otra cosa se define aquí, y puede sonar escaso, pero en realidad resulta muy flexible, ya que se puede definir una animación una vez y luego aplicarla a muchos elementos diferentes, con diferentes duraciones y otros comportamientos.
También se puede utilizar 0%
y 100%
en lugar de from
y to
. Si se desea, pueden incluirse fotogramas clave intermedios, para animaciones más complejas:
@keyframes spin {
0% { transform: rotate(0deg); }
25% { transform: rotate(30deg); }
50% { transform: rotate(120deg); }
100% { transform: rotate(360deg); }
}
Pueden escribirse fotogramas clave con los mismos valores en una sola línea, así:
25%, 50% {opacidad: 0,9;}
Nota
Puedes configurar la animación de manera que el primer fotograma clave no aparece en el 0% y lo haga, por ejemplo, en el 40%. Si lo haces, sin embargo, nada cambiará antes de ese punto en la animación. Si no se establece el último fotograma clave en un 100%, por ejemplo, 70%, la animación llegará a ese punto y permanecerá constante hasta el 100%.
Actualmente, la molestia principal de usar animaciones es que hay que definir un bloque de fotogramas clave diferente para cada navegador, ya que la propia regla utiliza un prefijo, y por tanto es necesario @-o-keyframes animation1 { }
, @-moz-keyframes animation1 { }
, etc. Y esto se suma a las diferentes versiones con prefijo de todas las propiedades de animación que veremos más adelante. Pero por lo menos dentro de cada regla con prefijo sólo es necesario incluir las propiedades individuales prefijadas para ese navegador, en el caso de propiedades que requieran prefijos. Y hay un par de librerías JavaScript que vale la pena estudiar, que detectan el motor de renderizado en tiempo de ejecución y añaden los prefijos apropiados cuando sea necesario, lo que ahorra tener que escribirlo todo. Véase Prefixfree, de Lea Verou, y Prefixr por Jeffrey Way.
Aplicar una animación
Para animar un elemento mediante esta animación, se aplican al elemento utilizando la propiedad animación-name
:
#image {
animation-name: spin;
}
Para hacer que esto haga algo, también hay que decir a la animación cuánto tiempo debe tomar para ejecutarse de principio a fin: esto se hace con antimation-duration
:
#image {
animation-name: spin;
animation-duration: 3s;
}
Estas son todas las propiedades necesarias para que una animación se ejecute una vez sobre un elemento. Veamos ahora qué otras propiedades tenemos para controlar animaciones.
¿Cuántas veces queremos que suceda?
Para hacer que nuestra animación se ejecute un determinado número de veces, se utiliza animation-iteration-count
:
#image {
animation-name: spin;
animation-duration: 3s;
animation-iteration-count: 10;
}
El valor de animation-iteration-count
puede ser cualquier número entero positivo, o puede ponerse a infinite
para hacer que funcione eternamente. El valor predeterminado es 1.
Para ver lo que tenemos hasta ahora en acción, echa un vistazo a mi ejemplo de spinner básico.
Variar la tasa de animación
El primer ejemplo no tiene mal aspecto, pero veréis que en cada iteración de la animación el sol comienza a girar rápidamente y luego se desacelera hasta detenerse. Se puede modificar la velocidad de cambio de la animación estableciendo diferentes valores de la propiedad animation-timing-function
. Los valores posibles son:
linear
hace que la animación suceda al mismo ritmo desde el principio hasta el final.ease
, el valor por defecto, hace que la animación se inicie rápidamente y se frene progresivamente, como ya hemos visto.ease-out
hace que la animación comience rápidamente, sigue rápido durante más tiempo que conease
y luego baje más abruptamente al final.ease-in
significa que la animación empieza poco a poco y luego acelera hacia el final.ease-in-out
significa que la animación comienza acelerando, es bastante rápida la mayor parte de la duración y se desacelera hacia el final.steps()
es ligeramente diferente. En lugar de dar una animación fluida continuamente, hace que la animación salte entre un número determinado de pasos repartidos de forma equidistante sobre la duración. Por ejemplo,steps(10)
haría que la animación saltase en diez etapas iguales. También hay un segundo parámetro opcional que toma un valor destart
oend
.steps(10,start)
especificaría que el cambio en el valor de la propiedad debería ocurrir al inicio de cada paso, mientras questeps(10,end)
significa el cambio vendría al final.cubic-bezier()
aplica una curva cúbica de Bézier a medida para dictar el cambio en la tasa de animación. Esta función toma cuatro argumentos: la coordenadas X e Y del control de inicio y las coordenadas X e Y del control final: por ejemplocubic-bezier(.28, 1.48, .9, .02)
.
Nota
¿No entiendes las cúbicas de Bézier? Lea Verou ha creado una fantástica herramienta visual que permite visualizar fácilmente su significado, ver los efectos de diferentes valores de la función e incluso generar tus propios valores. Échale un vistazo en cubic-bezier.com/.
Para hacer que el giro del sol parezca más consistente, puse animation-timing-function
a linear
: carga spinner lineal para ver el resultado.
Nota
Para crear un efecto de "rebote", se puede utilizar una cúbica de Bézier con valores de control de arrastre superiores a los límites inferior o superior de la gráfica, como por ejemplo, cubic-bezier(.2,-0.36,.71,1.45)
Retrasos de animación
Se puede establecer un retardo antes de que comience la animación, estableciendo una propiedad animation-delay
:
#image {
animation-delay: 4s;
}
Esta propiedad puede tomar valores positivos y negativos. Un valor positivo retrasa el inicio de la animación, mientras que un valor negativo hace que la animación comience en parte hacia la duración de animación specificada. Normalmente se usa esta opción cuando tienes varias animaciones que deseas disparar en diferentes momentos para montar una secuencia completa.
¿De principio a fin, o de ida y vuelta?
Por defecto, las animaciones que se ejecutan varias veces van desde el principio hasta el final, luego saltan hasta el principio y van hasta el final de nuevo, y así sucesivamente. Pero puede hacerse que la animación se haga de ida y vuelta: de principio a fin, del final al inicio, de principio a fin, y así sucesivamente, especificando animation-direction: alternate;
para el elemento que sea.
Para ver su efecto, echa un vistazo a mi ejemplo spinner alternativo. Ten en cuenta que el efecto de la función de tiempo se invierte también en las animaciones alternativas.
animation-fill-mode
La última propiedad que vamos a estudiar es animación-fill-mode
. Permite especificar cómo el elemento animado aparece al final de una animación o durante una animation-delay
. Los valores posibles de animation-fill-mode
son:
none
es el valor por defecto: cuando termina la animación del elemento al que se aplica vuelve a usar su estilo intrínseco. Además, ningún estilo de los fotogramas clave de la animación se aplicará al elemento durante un retardo de animación.forwards
hace que un elemento al que se ha aplicado una animación retenga los estilos definidos por las propiedades en el fotograma clave final después de que acabe la animación.animation-fill-mode: backwards
hace que los estilos definidos en el primer fotograma clave se apliquen al elemento al que se aplica la animación durante unanimation-delay
, en lugar de los estilos predeterminados para los elementos.both
aplica los efectos combinados deforwards
ybackwards
a un elemento al que se aplica una animación.
Para experimentar con algunos de estos efectos, he creado otro ejemplo incluye una animación que mueve el sol girando, y un retardo de animación. Luego he creado cuatro versiones, cada una de las cuales tiene un valor diferente de animation-fill-mode
:
animation-fill-mode: none
Nótese que el sol comienza en el centro de la pantalla, tal y como se define en el juego de reglas de #image, y luego salta a la posición definida en el fotograma clave 0% cuando comienza la animación. Al final de la animación, salta de nuevo al centro de la pantalla.animation-fill-mode: forwards
Aquí el sol comienza en la posición definida en el fotograma clave del 0%, y permanece allí hasta que comience la animación. Al final de la animación, salta de nuevo al centro de la pantalla.animation-fill-mode: backwards
En este caso, el sol comienza en el centro de la pantalla como se define en el juego de reglas de #image, y luego salta a la posición definida en el fotograma clave 0% cuando comienza la animación. Al final de la animación, se queda en la posición definida en el fotograma clave 100%.animation-fill-mode: both
El sol ahora comienza en la posición definida en el fotograma clave del 0%, y permanece allí hasta que comience la animación. Al final de la animación, se queda en la posición definida en el fotograma clave 100%.
Notación rápida para animación
Hay que escribir un montón de código para las animaciones CSS, puesto que hay que escribir varios bloques de fotogramas clave y propiedades múltiples, incluyendo todos los prefijos diferentes. Afortunadamente, se pueden usar abreviaturas para reducir seriamente la cantidad de código necesario.
Las siguientes propiedades:
animation-name: spin;
animation-duration: 3s;
animation-timing-function: linear;
animation-delay: 3s;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-fill-mode: both;
pueden ser sustituidas por esta línea:
animation: spin 3s linear 3s infinite alternate both;
La especificación de hecho no es muy específica al definir el orden exacto de los valores de las propiedades en la notación rápida, pero lo mejor es seguir con el orden que se indica aquí arriba para evitar posibles errores del navegador. Varias fuentes indican que este orden cumple con las idiosincrasias de los diferentes navegadores actuales.
Debe incluirse animation-name
y animation-duration
para que la animación haga algo. Si no se especifican explícitamente los otros valores, se aplicarán los valores predeterminados:
animation-timing-function: ease;
animation-delay: 0s;
animation-iteration-count: 1;
animation-direction: normal;
animation-fill-mode: none;
Pueden aplicar animaciones múltiples en una sola regla incluyéndolas en la misma propiedad, separadas por comas. Esto funciona tanto para la escritura corriente como para la notación rápida. He aquí un ejemplo:
animation: spin 3s, movement 5s;
animation-name: spin, movement;
animation-duration: 3s, 5s;
Si usted está utilizando las propiedades no abreviadas con diferente número de valores, es necesario especificar todos los nombres de animación que deben aplicarse. A partir de ahí, si alguna de las otras propiedades tiene menos valores que el número de animaciones especificado, se alternan para rellenar los huecos. Por ejemplo:
animation-name: spin, movement, glow;
animation-duration: 3s, 5s;
animation-delay: 2s;
La animación de giro tendrá una duración de 3 segundos, y la animación de movimiento tendrá una duración de 5 segundos. La animación glow tendrá un retraso de 3 segundos, ya que los valores de duración se han agotado, por lo que empieza desde el principio otra vez. Todas las animaciones tendrá un retraso de 2 segundos.
Un ejemplo más trabajado
Para terminar el artículo, he creado un ejemplo un poco más interesante con algunas animaciones más trabajadas: echa un vistazo a mi ejemplo de salida de sol. Si analizas el código verás una serie de animaciones que trabajan juntas para producir el efecto final.
Resumen
Eso concluye nuestro tour básico de las animaciones CSS: haznos saber tu opinión, y diviértete.