Las transiciones y animaciones CSS llevan entre nosotros algo más de una década pero, ¿por qué seguimos usando las mismas 4 opciones para hacer un poco menos planas las interfaces de usuario que desarrollamos? Una transición para la opacidad de 0 a 1 y ¡ya está!, haciendo que el potencial de las animaciones CSS se quede llorando en un rincón. No es que crea que hay que volver a esos "primeros" días de la web en las que todo era un festival de elementos parpadeantes, pero se puede dar un aspecto algo más aparente a nuestras apps y webs poniéndole un poquito de cariño a las transiciones y las animaciones.

¿Transición o animación?

Claramente no son lo mismo, puesto que no se llaman igual, pero ambas propiedades permiten a un elemento pasar de manera progresiva de un estado X a un estado Z.

Estos estados hacen referencia a algunas propiedades CSS que permiten ser transicionadas y/o animadas: opacity, visibility, background, width, height...

Un error común es tratar de animar una propiedad display con valor none a un valor block (o el que se necesite). Mi truco para saber si una propiedad CSS se puede transicionar/animar es preguntarme si existe esa propiedad con un valor intermedio: de no mostrarse (display: none) a mostrarse (display: block) no hay un valor "schrödinger-block" intermedio, por lo tanto esto nos indica que la propiedad display no es animable/transicionable. Pasa lo mismo con la propiedad visibility, pero no nos resulta tan evidente porque generalmente se utiliza junto a una transición/animación de opacidad.

Al final de este artículo encontraréis un listado de las propiedades CSS que son animables/transicionables.

¿Qué elegir? Pues depende de lo que queramos hacer. Si el efecto que queremos conseguir es una transformación lineal de un elemento, utilizaremos una transición, mientras que si queremos una mayor definición en el arco narrativo de la transformación, utilizaremos una animación.

¿Qué es una transición?

Cuando una propiedad en CSS cambia de un estado a otro, el cambio es instantáneo y brusco. Las transiciones CSS nos permiten pasar de un estado X a un estado Z a partir de un valor inicial hasta un valor final de manera gradual, siendo el navegador quien calcula los pasos intermedios y sin que nosotros podamos interferir en ellos.

El trigger que activará la transición vendrá definido por la cascada sobre un mismo elemento con dos selectores distintos, siempre y cuando la propiedad a transicionar no tenga un valor por defecto ¿Qué lío es este? Muy sencillo:

.my-btn {
    background: red;
    transition: background ease-in .3s;
}
.my-btn:hover {
    background: yellow
}

En este caso, la propiedad background no tiene un valor por defecto y por tanto, debemos hacer la transición entre dos estados determinados por la regla css que declaramos (el estado normal y el hover). Hay algunas propiedades que, al tener un valor por defecto, sólo tendremos que indicar el valor final, como ocurre en las transformaciones:

.mt-btn {
    transition: ease-in .4s;
}

.mt-btn:hover {
    transform: scale(2.5);
}

Las transiciones se utilizan para animar propiedades CSS siguiendo una curva de aceleración, con un retraso en el inicio opcional, de un valor inicial a un valor final durante un periodo de tiempo determinado, y para todo ello usaremos lo siguiente:

transition-property: la propiedad css que vamos a transicionar
transition-duration: la duración de la transición
transition-timing-function: la "forma" en la que la transición tendrá lugar
transition-delay: el retraso que queremos aplicarle al inicio de la transición

¿Qué es una animación?

Las animaciones nos permiten, al igual que las transiciones, pasar un elemento del estado X al estado Z, permitiendo definir un número variable de estados intermedios. Es decir, nos ofrecen un mayor control sobre el cambio de estado y las fases que atraviesa este.

Las animaciones, además, no necesariamente tienen que ejecutarse cuando sucede un cambio de estado en el elemento, sino que se ejecutarán en el keyframe que indiquemos al definirlas. Por supuesto, pueden utilizarse en cambios de estado, pero no es una condición obligatoria, mientras que en la transición sí. Para entender mejor esto, imaginaos un botón que cambia de color: una transición se ejecutaría cuando hay una interacción en ese botón que lo hace cambiar de estado, como puede ser un hover, mientras que si aplicamos una animación, este botón puede estar cambiando de color desde el momento en el que se renderiza, sin necesidad de interacción con él por parte del usuario.

Otra diferencia, usando el mismo ejemplo del botón que cambia de color, es una transición en la que el color inicial es azul, y el final morado (los colores que se mostrarán durante la transición serán intermedios entre el azul y el morado). Mientras que con una animación, el color inicial puede ser el azul, el final el morado y podremos definir distintos colores intermedios.

Los keyframes son la regla que nos permite establecer el nombre de nuestra animación, que posteriormente indicaremos con la propiedad animation-name sobre el elemento a animar.

Además del nombre, la regla keyframe nos permite definir los fotogramas clave que tendrá la animación mediante bloques definidos por un valor en %, como se muestra a continuación:

@keyframe my-animation { /* al definir los keyframes de la animación también la otorgamos un nombre*/
    0% {
        transform: scale(1, 1);
    }
    30% {
        transform: scale(0.92, 0.95);
    }
    50%{
        transform: scale(1, 1);
    }
    80% {
        transform: scale(0.92, 0.95);;
    }
    100% {
        transform: scale(1, 1);
    }
}

Los valores porcentuales se calculan en base a la duración del ciclo completo de la animación, que definiremos con la propiedad animation-duration.

En ocasiones, también se utilizan dos bloques definidos por las palabras clave: from y to, que definen el estado inicial y final de la animación:

@keyframe my-animation {
    from {
        transform: scale(1, 1);
    }
    50% {
        transform: scale(1, 1);
    }
    30%, 80% {
        transform: scale(0.92, 0.95);
    }
    to {
        transform: scale(1, 1);
    }
}

See the Pen yLGbBQR by @NoemiMS on CodePen.

En el caso en el que no definamos dentro de la animación un fotograma from/0% o to/100%, el navegador utilizará el valor de las propiedades animadas que estén definidas en el elemento que estamos animando. En el caso del fotograma from/0% es más sencillo de "ver", pero hay que tener cuidado con el fotograma to/100%, ya que podría jugarnos malas pasadas. En el ejemplo de código anterior, si eliminásemos el fotograma “to”, y el elemento al que aplicamos la animación tuviera una opacity: 1, la animación terminaría con el elemento con esa opacidad, y quizá no es lo que buscamos con nuestra animación.

Pero las animaciones no sólo nos permiten controlar los pasos intermedios de la propia animación, sino que amplía las propiedades con las que podemos controlar su ejecución:

animation-duration: el tiempo en el cual se ejecuta cada ciclo de la animación
animation-timing-function: la "forma" en la que la animación tendrá lugar
animation-delay: el retraso que queremos aplicarle al inicio de la animación
animation-name: el nombre que hayamos dado a la animación.
animation-direction: el "sentido" en el que se ejecutará la animación
animation-iteration-count: podemos definir cuantos ciclos va a tener la animación (cuantas veces se repetirá)
animation-play-state: podemos definir si en el momento del renderizado de la página, la animacion está ejecutándose o en pausa
animation-fill-mode: podemos definir qué keyframe será visible cuando la animación no se esté ejecutando

Más detalles sobre dos de estas propiedades:

Por último, el orden en el que se ejecutan las animaciones sobre una propiedad respetará la cascada de CSS. Es decir, si existen varias animaciones que definen valores para la misma propiedad, el valor especificado en la última animación aplicada anulará los de las animaciones anteriores.

Timing functions y tiempo

Las funciones de tiempo que aplicamos a las animaciones y transiciones están basadas en las curvas cúbicas de Bézier, que se desarrolló para el diseño aeronáutico y de automoción. Pero como aquí lo único que queremos hacer con cohetes y coches es moverlos de un lado a otro de un <div>, vamos a simplificar con las timing-functions que se utilizan para determinar la velocidad en CSS:

See the Pen BavRPjJ by @NoemiMS on CodePen.

Un buen recurso para hacer esta curva "custom" es esta web, dónde podéis definir en la curva lo que queréis y ver una comparación con una curva de las predefinidas. Otra herramienta interesante para conseguir la curva de tiempo que mejor encaja con nuestra animación es esta, donde hay unas 30 curvas predefinidas que podemos ver en acción y compararlas con un ejemplo de animación linear.

Siento deciros esto, pero no hay una fórmula mágica para el uso del timing a la hora de animar elementos en la web, a pesar de que es el principio más importante de las animaciones y las transiciones. Las unidades de tiempo son ínfimas, y ajustar al milisegundo para conseguir un efecto natural en la animación que queremos es tedioso y, principalmente, una cuestión de ensayo y error. Además, el timing que nos funcione para una función de tiempo ease-in no va a funcionar con una función de tiempo definida por nosotros, y viceversa.

Y no podemos olvidar lo importante que es la coreografía entre todos los elementos animados que tengamos. Pensad que no existe el número adecuado de animaciones, y que todo finalmente dependerá del diseño que estemos implementando, pero como usuarios sabemos que muchas animaciones pueden resultar molestas. Coreografiar nuestras animaciones nos proveerá de una cohesión que hará que las animaciones jueguen en nuestro favor con respecto a la experiencia de usuario.

Relación con JS & performance

Las animaciones y transiciones que conseguimos con CSS son lo suficientemente válidas y performáticas como para no necesitar la interacción de JavaScript en ellas.

Las transiciones generalmente pueden "replicarse" en JavaScript, pero teniendo en cuenta que contamos con herramientas en CSS para hacerlo, ¿por qué optar por JavaScript? Es cierto que quizá existan casos en los que los valores de alguna propiedad de la transición tengan que ser manipulados a través de JS, pero eso no implica que toda la transición se haga con JS (aunque se pueda).

En el caso de las animaciones, tratar de replicarlas en JS implica tal sobre ingeniería que apelar a la Ockham y su navaja te evitará muchos quebraderos de cabeza.

En cuanto a la performance entre animaciones/transiciones CSS vs animaciones con JS, a día de hoy las diferencias entre unas y otras son completamente despreciables, así que no es un dato a tener en cuenta a la hora de decantarse por unas u otras.

Conclusión

En definitiva, las animaciones y las transiciones nos permiten mejorar la experiencia de usuario y no son un terreno pantanoso en el que adentrarnos ya que, como habéis podido ver, conociendo sus características sólo hace falta algo de tiempo para manejarlas con soltura y poder jugar con ellas, sin necesidad de copiar y pegar de algún codepen o incluir una librería de animaciones que no necesitamos. Además, si desde que pensamos nuestra arquitectura CSS ponemos énfasis en las animaciones y transiciones que queremos incluir en nuestro proyecto, podremos crearnos nuestra propia pequeña librería.

Como consejo personal os diré que es muy gratificante terminar una animación y haber conseguido el resultado que esperábamos. Es lo más parecido a hacer magia que vamos a lograr muchos de nosotros :).

Anexo

Propiedades CSS a las que se les pueden aplicar animaciones y/o transiciones:

Cuéntanos qué te parece.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.

Suscríbete

Estamos comprometidos.

Tecnología, personas e impacto positivo.