Sebastian Gomez
Todo sobre Animaciones en CSS
Las animaciones en CSS son un conjunto de herramientas que nos permite mostrar contenido de una manera más dinámica y llamativa para las personas que usan nuestro sitio web. Su principal ventaja frente a las transiciones es que nos da un control más granular de los estados de la animación mediante los @keyframes. Veamos un ejemplo de una animación simple en la forma abreviada:
.animated-thing {
animation: black-to-white 1s linear 1;
}Ahora veamos la misma animación en la forma larga:
.animated-thing {
animation-name: black-to-white;
animation-duration: 1s;
animation-timing-function: linear;
animation-iteration-count: 1;
animation-delay: 0s;
}El nombre de la animación hace referencia al keyframe respectivo. Los @keyframes en CSS los podemos definir como los puntos de trayectoria de una animación; es decir, nos permiten definir qué valores deben alcanzar las propiedades que estamos animando a lo largo de la secuencia. Esto nos da un control más específico sobre los pasos intermedios.
@keyframes black-to-white {
0% {
}
25%,
35% {
}
100% {
}
}También se pueden utilizar formas abreviadas:
@keyframes black-to-white {
from {
}
to {
}
}También puedes usar más de un keyframe a la vez, separando con comas las diferentes animaciones:
.animated-thing {
animation: black-to-white 1s linear 1, black-to-red 2s ease-out infinite 2s;
}Una consideración a tener en cuenta es que los nombres de la animación no pueden empezar con números o caracteres especiales. Por ejemplo, "1st-animation" no sería un nombre válido para la animación.
Animación de sprites usando CSS
La animación de sprites es una de las técnicas más avanzadas que se pueden lograr con CSS. Primero es necesario entender qué es un sprite: un sprite es una imagen gráfica única que se incorpora a una escena más grande para que parezca ser parte de ella.
A continuación verás un ejemplo de una hoja de sprites de un personaje. Cada secuencia de movimiento ocupa el mismo espacio que las demás y, al ponerlas juntas a determinada velocidad, nos permite "percibir" que hay movimiento en el personaje.
Para hacer una animación de sprite efectiva en CSS no nos basta con las funciones de temporización linear, ease-in, ease-out, ease-in-out o cubic-bezier, ya que en cualquiera de esos casos veríamos el movimiento de los frames desplazándose suavemente de un lado a otro. Ahí es donde entra la función steps(x), donde x es el número de cuadros que tiene tu hoja de sprites. steps(x) divide un bloque de keyframes en x pasos iguales y luego salta entre ellos. Veamos un ejemplo de cómo animar el personaje del sprite anterior:
.walking-front {
background: url(/images/sprites/walking-front.png) 0 0 no-repeat;
animation: walking-front 1s steps(4) infinite;
height: 48px;
width: 32px;
margin: 50px auto 0;
}
@keyframes walking-front {
0% {
background-position: 0 0;
}
100% {
background-position: -128px 0;
}
}Nota: sirve tu hoja de sprites desde tu propio dominio por HTTPS (por ejemplo, desde la carpeta public/). Las imágenes externas enlazadas por http:// suelen desaparecer con el tiempo y, además, el navegador las bloquea como contenido mixto en un sitio servido por HTTPS.
Como buena práctica, se sugiere no declarar el 0% si el estado inicial coincide con el de la imagen, por lo que una versión reducida podría quedar así:
@keyframes walking-front {
100% {
background-position: -128px 0;
}
}Hay también tres propiedades importantes que deberías conocer cuando estás creando animaciones en CSS. A diferencia de los pasos 0%, 100%, etc., estas propiedades no van dentro de @keyframes: se aplican directamente al elemento, junto con las demás propiedades animation-* (como animation-name o animation-duration). Estas son:
.animated-thing {
/* Controla qué estilos se conservan antes y/o después de ejecutar la
animación. forwards mantiene el estado final, backwards aplica el
inicial durante el delay, both hace ambas cosas y none es el valor
por defecto. */
animation-fill-mode: forwards; /* forwards | backwards | both | none */
/* Controla el estado de la animación: si está corriendo o pausada. */
animation-play-state: running; /* running | paused */
/* Controla la dirección de reproducción. Si la animación se ejecuta
infinitamente, alternate hace que vaya y vuelva indefinidamente. */
animation-direction: alternate; /* normal | reverse | alternate | alternate-reverse */
}Puedes controlar el estado de una animación con JavaScript usando los siguientes eventos (listeners):
animationstartanimationendanimationiteration
En los siguientes ejemplos se muestra un conjunto de animaciones con sprites, cada una con distintas propiedades. Puedes jugar con ellas para evidenciar sus diferencias:
- CodePen: animación de sprites 1
- CodePen: animación de sprites 2
- CodePen: animación de sprites 3
- CodePen: animación de sprites 4
Personalmente sigo a Rachel Nabors, una de mis grandes heroínas en el mundo de la animación.
Consideraciones finales
Finalmente, algunas consideraciones sobre las animaciones:
- Pueden hacer loop infinitamente.
- Poseen autoinicio: no requieren un disparador como las transiciones.
- Se pueden alternar entre el estado final (
end) y el inicial (start). - Se pueden agrupar distintas propiedades.
- Úsalas para indicar que un elemento cambia de dirección, de estado o de momentum.
Las animaciones de entrada ("animations in") son más fáciles que las de salida ("animations out"). Por eso verás miles de sitios con animaciones de entrada que, una vez que terminan, difícilmente regresan de buena manera al estado original.
Existen tres tipos de animaciones:
- Supplemental Animations: aquellas que no están relacionadas con la información inicial.
- Decorative Animations: solo aportan decoración, y nunca deberías tener más de una.
- Stateful Animations: el core de tu animación; animan contenido importante o un call to action y resaltan detalles que la persona no debería pasar por alto.
Una nota sobre el rendimiento
Si tienes problemas de rendimiento con tus animaciones, o si simplemente quieres optimizar el flujo, la propiedad recomendada hoy es will-change. Le indica al navegador, de forma intencional, qué propiedad vas a animar para que prepare la composición por adelantado y delegue el trabajo a la GPU:
.animated-thing {
will-change: transform;
}Nota: usa will-change con moderación, solo en los elementos que realmente vas a animar, porque reservar capas de composición tiene un costo de memoria. Antiguamente se recomendaba el truco transform: translateZ(0) (o translate3d(0, 0, 0)) para forzar la aceleración por hardware en vez de dejar el trabajo al navegador. Hoy will-change es la opción moderna e intencional, y translateZ(0) queda solo como recurso heredado para navegadores muy antiguos.
Ejercicios propuestos
- Crea una animación simple en la forma abreviada y reescríbela en la forma larga. Comprueba que ambas producen el mismo resultado.
- Anima una hoja de sprites propia con
steps()y experimenta cambiando el número de pasos para ver cómo afecta al movimiento. - Usa
animation-direction: alternateen una animación infinita y añade un listener deanimationiterationque cuente las repeticiones por consola.
Resumen
- Las animaciones en CSS se basan en
@keyframesy en las propiedadesanimation-*, que se aplican al elemento, no dentro de@keyframes. - La función
steps()es clave para animar hojas de sprites de forma convincente. - Para optimizar el rendimiento, da prioridad a
will-change: transformy dejatranslateZ(0)como recurso heredado.
Eso es todo, espero que este post te sea de utilidad y lo puedas aplicar a algún proyecto que tengas en mente, o que simplemente te haya ayudado a entender la naturaleza de las animaciones en CSS. Déjame un comentario si lograste implementarlo, si quieres añadir alguna funcionalidad o si tienes alguna duda. Y recuerda que, si te gustó, también puedes compartirlo usando los links a las redes sociales aquí abajo.
Sebastian Gomez
Creador de contenido principalmente acerca de tecnología.