Skip to content

Animaciones CSS

Posted on:12 de julio de 2020

Este artículo es parte de una serie de artículos dedicados a la Animación Web.

Animación CSS con @keyframes

En CSS, a parte de poder animar cambios de estados con Transiciones CSS, tenemos disponible la propiedad animate que junto con la regla arroba (at-rule) @keyframes nos permite poder definir una animación controlando el tiempo, múltiples estados (keyframes o fotogramas), número de repeticiones, dirección de la animación y la función de tiempo, para conseguir una animación más natural.

Antes de entrar en detalles, analizando cada una de las propiedades y sus valores, veamos un ejemplo de una animación.

¿Qué podemos animar en una web?

La propiedad animation nos permite animar muchas de las propiedades CSS: color, posición, márgenes, paddings (no puedo llamarle rellenos 😅), opacidad o tamaños. Tanto en la W3C, como en la MDN encontraremos una tabla de características de la propiedad. Una de esas características nos informa del Animation Type, que nos indica el tipo de animación que soporta esa propiedad not animatable, discrete, by computed value o repeatable list.

En este enlace de la MDN encontrarás una lista de las propiedades CSS que se pueden animar. O este otro donde además hay un ejemplo de cada una de ellas.

La propiedad animation

Hay varias propiedades para definir y configurar una animación, como en muchas de las propiedades CSS, lo podemos hacer con shorcut o definiendo cada una de ellas.

Creo que es mejor conocer las propiedades, y qué hacen, que memorizar el orden de los valores… así que vamos a ver todas la propiedades animation-*.

.logo {
  animation-name: logoAnimation;
  animation-duration: 2s;
  animation-timing-function: ease-in-out;
  animation-delay: 1s;
  animation-iteration-count: infinite;
  animation-direction: normal;
  animation-fill-mode: forwards;
  animation-play-state: initial;
}

animation-name

Con esta propiedad definimos el nombre o nombres de la animación o animaciones que queremos aplicar al elemento, este nombre debe coincidir con uno de los @keyframes que tengamos definidos, pero en un rato lo vemos.

animation-duration

Bueno, no es difícil intuir que con esta propiedad podemos definir la duración de la animación o animaciones, lo podemos hacer indicándola en segundos o milisegundos.

animation-timing-function

En mi opinión, esta es la propiedad de animación más interesante. No permite indicar una función de tiempo que se aplicará ajustándose a la duración de la animación. Tenemos unas cuantas funciones predefinidas, que harán que nuestras animaciones tengan un aspecto más natural.

Creo que esta propiedad merece un artículo y vídeo dedicado para ver todo su potencial, así que hoy solo veremos los aspectos más básicos.

Acepta valores de “keyword” y de funciones:

/* Keyword values */
animation-timing-function: ease;
animation-timing-function: ease-in;
animation-timing-function: ease-out;
animation-timing-function: ease-in-out;
animation-timing-function: linear;
animation-timing-function: step-start;
animation-timing-function: step-end;

/* Function values */
animation-timing-function: cubic-bezier(0.1, 0.7, 1, 0.1);
animation-timing-function: steps(4, end);

El valor por defecto es ease y se representa así:

ease timing function

El eje horizontal representa el tiempo de la animación y el vertical representa los valores que se están cambiando en la animación.

De esta forma conseguimos una animación más fluida, en lugar de una animación lineal. Pero ojo, que una animación lineal puede tener sentido en algunas ocasiones, pero lo veremos con ejemplos en el capítulo específico de las CSS Easing Functions.

De momento nos quedamos con que esta propiedad nos permite tener control de cómo se va a calcular la línea temporal de la animación.

animation-delay

De igual forma que tenemos una propiedad para definir el tiempo de la animación, también podemos definir cuanto tiempo debe pasar hasta que empiece la animación. También podemos definir el tiempo con segundos y milisegundos, eso sí, podemos definir un delay negativo, lo que afecta a la línea de tiempo de la animación.

Si tenemos una animación de 2 segundos y definimos un animation-delay: -1s la animación empezará a ejecutarse de forma inmediata y además empezará en el segundo 1.

animation-delay

animation-iteration-count

Con animation-iteration-count podemos definir el número de veces que se ejecutará la animación, acepta un número de valor positivo o la palabra clave infinite, como en el ejemplo, esto hace que la animación se ejecute de forma infinita.

animation-direction

Esta propiedad nos permite indicar la dirección de la animación, acepta 4 valores, veamos las definiciones para entender mejor en qué nos puede ayudar esta propiedad.

normal Cada vez que termina un ciclo, la animación se reinicia al estado inicial y comienza desde el principio. Este es el comportamiento por defecto.

alternate La animación, al terminar un ciclo, invierte su dirección. Es decir, los pasos de la animación se ejecutan al revés. Además, las funciones de tiempo también se invierten; por ejemplo una animación ease-in se convierte en una animación con ease-out cuando se reproduce al revés.

reverse Cada ciclo de la animación se reproduce al revés . Cada vez que comienza un ciclo de animación, ésta se posiciona en el estado final y comienza desde ahí.

alternate-reverse Es similar a alternate pero la animación se reproduce al revés. Es decir la animación se posiciona en el estado final, comienza a reproducirse al revés y, cuando llega al inicio vuelve a reproducirse de forma normal hasta llegar al final de la secuencia.

animation-fill-mode

animation-fill-mode es la propiedad que nos permite definir el estado después de la animación, y también el estado antes de la animación si existiese delay. Por defecto vuelve a su estado inicial, con el valor normal.

animation-fill-mode

Dibujo de Ángel Corral

Aquí podemos ver qué pasa si aplicamos un valor de forwards.

Otro de los valores interesantes de esta propiedad es both, funcionará igual que forwards pero tendrá en cuenta el sentido de la animación. ¿Recordáis que con animation-direction podemos hacer que la animación sea invertida?, pues este valor nos ayudará a definir el comportamiento que deseemos en nuestras animaciones.

animation-play-state

Esta propiedad también es muy interesante, ya que nos permite dotar de interactividad nuestra animación desde CSS, sin utilizar JavaScript. Ya veremos más adelante cómo trabajar las animaciones con JavaScript, la API de animación es genial… bueno no nos despistemos 😊.

Los valores disponibles son:

/* Single animation */
animation-play-state: running;
animation-play-state: paused;

/* Global values */
animation-play-state: inherited;
animation-play-state: initial;
animation-play-state: unset;

El valor por defecto es running, y podemos hacer una pausa cambiando su estado. Pero mejor veamos un ejemplo:

Seguro que has visto que no hay ninguna animación, eso es porque he definido un estado inicial de la animación pausada animation-play-state: paused;, y con un hover en el body cambio el estado de la animación a running. Prueba a poner el cursor, perdón a la gente que esté leyendo esto desde un dispositivo móvil 😅, en área de Result. Verás que la animación se ejecuta y pausa según haces hover o no sobre el body del documento.

Los shorthands y valores por defecto

El shorthands animation

Por norma general cuando veamos un código CSS con una animación veremos algo como esto:

.logo {
  animation: scale 2s infinite ease-in;
}

Es la forma abreviada de definir una animación. La especificación define un orden para los parámetros, así se facilita la compatibilidad entre los navegadores a la hora de su implementación.

.logo {
  animation: "animation-name" "animation-duration" "animation-timing-function"
    "animation-delay" "animation-iteration-count" "animation-direction"
    "animation-fill-mode";
}

Los pongo uno bajo el otro para mejorar la legibilidad, pero se definen todos en la misma línea y sin separarlos por una coma. Aunque ese es el orden definido por la W3C, si se cambia el orden, los navegadores son lo suficientemente inteligentes para entender cada uno de los valores a qué hace referencia. Una cosa a tener en cuenta es el duration y el delay, si solo hay un valor de tiempo, el navegador interpretará que es duration y si hay dos, el primero será duration y el segundo será para definir el delay.

Los valores por defecto

En los ejemplos que hemos ido viendo, he definido valor a todas las propiedades por temas docentes, pero hemos de tener en cuenta que la ausencia de alguna de esas propiedades se representarán con su valor por defecto.

Por ejemplo, no hace falta definir animation-timing-function: ease o animation-delay: 0s, ya que son los valores por defecto.

Los @keyframes

Hasta ahora hemos visto todas las propiedades de tiempo, función, iteraciones, etc… para añadir la animación a una clase, pero, ¿dónde creamos o definimos la animación?

Aquí entran en escena los @keyframes. Como vimos en el artículo de las Transiciones CSS, con las transiciones podemos hacer que el navegador haga una interpolación entre dos estados y conseguir así, una animación. Pero cuando queremos tener una animación con más de 2 estados tenemos que utilizar los @keyframes.

Animación Web

Los keyframes hacen referencia a los fotogramas de la animación, y podemos definir los que necesitemos, vamos a ver el códico de la animación que hemos estado utilizando como ejemplo.

@keyframes logoAnimation {
  0% {
    opacity: 0;
    transform: translateX(-100px);
  }
  20%,
  80% {
    opacity: 1;
    transform: translateX(0);
  }
  100% {
    opacity: 0;
    transform: translateX(100px);
  }
}

Lo primero que vemos es que no estamos definiendo un selector, sino un at-rule (como @media, @support, @font-face, etc…), es @keyframe segido del nombre que queremos que tenga la animación. Ese nombre es el identificador que estamos utilizando en la propiedad animation-name. Seguimos con un bloque, como también hacemos en las clases, pero en esta ocasión no definimos propiedades CSS, definimos bloques de keyframes donde en su interior escibiremos las propiedades CSS que queremos animar… ahora es cuando empieza lo emocionante 😊.

Para definir los keyframes (fotogramas), tenemos dos maneras de hacerlo, mediante palabras clave o con porcentajes.

@keyframes <identifier> {
  [ [ from | to | <percentage> ] [, from | to | <percentage> ]* block ]*
}

from equivale al 0% y to equivale al 100%.

Estas dos animaciones son equivalentes, es totalmente indiferente desde el punto de vista del navegador.

@keyframes logoAnimation_keyworks {
  from {
    opacity: 0;
    transform: translateX(-100px);
  }
  to {
    opacity: 1;
    transform: translateX(0px);
  }
}

@keyframes logoAnimation_percentage {
  0% {
    opacity: 0;
    transform: translateX(-100px);
  }
  100% {
    opacity: 1;
    transform: translateX(0px);
  }
}

Incluso podemos mezclar las palabras clave y los porcentajes.

@keyframes logoAnimation {
  from {
    opacity: 0;
    transform: translateX(-100px);
  }
  20%,
  80% {
    opacity: 1;
    transform: translateX(0);
  }
  to {
    opacity: 0;
    transform: translateX(100px);
  }
}

Animaciones múltiples

Igual que en las transiciones, la animaciones admiten definir múltiples animaciones. Esto nos permite tener un mayor control si queremos hacer una animación secuencial.

En este ejemplo he creado una secuencia de 4 animaciones.

.logo {
  animation: fadeIn 1s ease-in forwards, growth 1s 1s ease-in forwards,
    fadeOut 1s 2s ease-out forwards, logoAnimation 500ms 3s ease-in forwards;
}
Secuencia de animaciones

Controlamos la secuencia de las animaciones con la propiedad animation-delay, sumando el tiempo de las animaciones anteriores.

Esto es un trabajo muy artesanal y nada escalable, pero eso ya lo veremos cuando trabajemos con las animaciones con JavaScript.

Conclusión

Hasta aquí hemos visto lo básico de la animación con CSS, en la implementación encontraremos algunos casos donde hay que conocer bien las posibilidades de las propiedades CSS. En futuros capítulos veremos ejemplos de implementación, depuración, optimización y buenas prácticas.