El movimiento es una parte fundamental de cualquier experiencia digital, ya que guía al usuario de una interacción a la siguiente. Sin embargo, hay algunos vacíos en las animaciones fluidas en la plataforma web. Estas incluyen la capacidad de animar fácilmente animaciones de entrada y salida, y realizar animaciones fluidas hacia y desde la capa superior para elementos descartables, como diálogos y ventanas emergentes.
Para llenar esos vacíos, Chrome 116 y 117 incluyen cuatro nuevas funciones de plataforma web que permiten crear transiciones y animaciones fluidas para propiedades discretas.
Estas cuatro funciones nuevas incluyen las siguientes:
- La capacidad de animar
display
ycontent-visibility
en un cronograma de fotogramas clave (a partir de Chrome 116) - La propiedad
transition-behavior
con la palabra claveallow-discrete
para habilitar las transiciones de propiedades discretas, comodisplay
(a partir de Chrome 117) - La regla
@starting-style
para animar los efectos de entrada dedisplay: none
y la capa superior (a partir de Chrome 117) - La propiedad
overlay
para controlar el comportamiento de la capa superior durante una animación (a partir de Chrome 117) ## Cómo mostrar animaciones en fotogramas clave
A partir de Chrome 116, puedes usar display
y content-visibility
en las reglas de fotogramas clave. Estos se cambiarán en el momento en que se produzca el fotograma clave. No se requieren valores nuevos adicionales para admitir esto:
.card {
animation: fade-out 0.5s forwards;
}
@keyframes fade-out {
100% {
opacity: 0;
display: none;
}
}
En el ejemplo anterior, se anima la opacidad a 0 durante los 0.5 s de duración y, luego, se establece la visualización en “none”. Además, la palabra clave forwards
garantiza que la animación permanezca en su estado final, de modo que el elemento al que se aplica permanezca display: none
y opacity: 0
.
Este es un ejemplo simple que imita lo que puedes hacer con una transición (consulta la demostración en la sección de transición). Sin embargo, las transiciones no pueden crear animaciones más complejas, como en el siguiente ejemplo:
.card {
animation: spin-and-delete 1s ease-in forwards;
}
@keyframes spin-and-delete {
0% {
transform: rotateY(0);
filter: hue-rotate(0);
}
80% {
transform: rotateY(360deg);
filter: hue-rotate(180deg);
opacity: 1;
}
100% {
opacity: 0;
display: none;
}
}
La animación spin-and-delete
es una animación de salida. Primero, la tarjeta girará en el eje Y, pasará por una rotación de tono y, luego, en 80%
por el cronograma, cambiará su opacidad de 1 a 0. Por último, la tarjeta cambia de display: block
a display: none
.
Para estas animaciones de salida, en lugar de aplicarlas directamente a un elemento, puedes configurar un disparador para las animaciones. Por ejemplo, si adjuntas un objeto de escucha de eventos a un botón que active una clase para aplicar la animación, de la siguiente manera:
.spin-out {
animation: spin-and-delete 1s ease-in forwards;
}
document.querySelector('.delete-btn').addEventListener('click', () => {
document.querySelector('.card').classList.add('spin-out');
})
El ejemplo anterior ahora tiene un estado final de display:none
. En muchos casos, querrás avanzar más y quitar el nodo del DOM con un tiempo de espera para permitir que la animación finalice primero.
Cómo realizar la transición de animaciones discretas
A diferencia de lo que ocurre cuando se animan propiedades discretas con fotogramas clave, para realizar la transición de propiedades discretas deberás usar el modo de comportamiento de transición allow-discrete
.
La propiedad transition-behavior
El modo allow-discrete
es lo que hace posibles las transiciones discretas y es un valor de la propiedad transition-behavior
. transition-behavior
acepta dos valores: normal
y allow-discrete
.
.card {
transition: opacity 0.25s, display 0.25s;
transition-behavior: allow-discrete; /* Note: be sure to write this after the shorthand */
}
.card.fade-out {
opacity: 0;
display: none;
}
La abreviatura transition
también establece este valor, por lo que puedes omitir la propiedad y usar la palabra clave allow-discrete
al final de la abreviatura transition
para cada transición.
.card {
transition: opacity 0.5s, display 0.5s allow-discrete;
}
.card.fade-out {
opacity: 0;
display: none;
}
Si estás animando varias propiedades discretas, deberás incluir allow-discrete
después de cada propiedad que desees animar. Por ejemplo:
.card {
transition: opacity 0.5s, display 0.5s allow-discrete, overlay 0.5s allow-discrete;
}
.card.fade-out {
opacity: 0;
display: none;
}
La regla @starting-style
para las animaciones de entradas
Hasta ahora, en este artículo, se trataron las animaciones de salida. Para crear animaciones de entrada, debes usar la regla @starting-style
.
Usa @starting-style
para aplicar un estilo que el navegador pueda buscar antes de que el elemento se abra en la página. Este es el estado “antes de abrir” (desde el que realizas la animación).
/* 0. BEFORE-OPEN STATE */
/* Starting point for the transition */
@starting-style {
.item {
opacity: 0;
height: 0;
}
}
/* 1. IS-OPEN STATE */
/* The state at which the element is open + transition logic */
.item {
height: 3rem;
display: grid;
overflow: hidden;
transition: opacity 0.5s, transform 0.5s, height 0.5s, display 0.5s allow-discrete;
}
/* 2. EXITING STATE */
/* While it is deleting, before DOM removal in JS, apply this
transformation for height, opacity, and a transform which
skews the element and moves it to the left before setting
it to display: none */
.is-deleting {
opacity: 0;
height: 0;
display: none;
transform: skewX(50deg) translateX(-25vw);
}
Ahora tienes un estado de entrada y de salida para estos elementos de la lista de tareas pendientes:
Cómo animar elementos desde y hacia la capa superior
Para animar elementos hacia y desde la capa superior, especifica el @starting-style
en el estado "open" para indicarle al navegador desde dónde debe animar. En el caso de un diálogo, el estado abierto se define con el atributo [open]
. Para una ventana emergente, usa la pseudoclase :popover-open
.
Un ejemplo simple de un diálogo podría verse así:
/* 0. BEFORE-OPEN STATE */
@starting-style {
dialog[open] {
translate: 0 100vh;
}
}
/* 1. IS-OPEN STATE */
dialog[open] {
translate: 0 0;
}
/* 2. EXIT STATE */
dialog {
transition: translate 0.7s ease-out, overlay 0.7s ease-out allow-discrete, display 0.7s ease-out allow-discrete;
translate: 0 100vh;
}
En el siguiente ejemplo, los efectos de entrada y salida son diferentes. Para ingresar, mueve la imagen hacia arriba desde la parte inferior del viewport y sal del efecto en la parte superior. También está escrito con CSS anidada para lograr un encapsulamiento más visual.
Cuando animes una ventana emergente, usa la seudoclase :popover-open
, en lugar del atributo open
que se usó anteriormente.
.settings-popover {
&:popover-open {
/* 0. BEFORE-OPEN STATE */
/* Initial state for what we're animating *in* from,
in this case: goes from lower (y + 20px) to center */
@starting-style {
transform: translateY(20px);
opacity: 0;
}
/* 1. IS-OPEN STATE */
/* state when popover is open, BOTH:
what we're transitioning *in* to
and transitioning *out* from */
transform: translateY(0);
opacity: 1;
}
/* 2. EXIT STATE */
/* Initial state for what we're animating *out* to ,
in this case: goes from center to (y - 50px) higher */
transform: translateY(-50px);
opacity: 0;
/* Enumerate transitioning properties,
including display and allow-discrete mode */
transition: transform 0.5s, opacity 0.5s, display 0.5s allow-discrete;
}
overlay
propiedad
Por último, para aplicar fundido de salida popover
o dialog
en la capa superior, agrega la propiedad overlay
a tu lista de transiciones. popover
y dialog
escapan a los clips principales y las transformaciones, y también colocan el contenido en la capa superior. Si no realizas la transición de overlay
, tu elemento volverá inmediatamente a recortarse, transformarse y cubrirse, y no verás la transición.
[open] {
transition: opacity 1s, display 1s allow-discrete;
}
En su lugar, incluye overlay
en la transición o animación para animar overlay
junto con el resto de las funciones y asegúrate de que permanezca en la capa superior durante la animación. Esto se verá mucho más fluido.
[open] {
transition: opacity 1s, display 1s allow-discrete, overlay 1s allow-discrete;
}
Además, cuando tienes varios elementos abiertos en la capa superior, la superposición te ayuda a controlar la transición fluida de entrada y salida de la capa superior. Puedes ver la diferencia en este ejemplo sencillo. Si no aplicas overlay
a la segunda ventana emergente durante la transición, primero se moverá fuera de la capa superior, y se ubicará detrás de la otra ventana emergente, antes de comenzar la transición. No es un efecto muy fluido.
Nota sobre las transiciones de vistas
Si realizas cambios en el DOM, como agregar y quitar elementos del DOM, otra excelente solución para crear animaciones fluidas son las transiciones de vistas. Estos son dos de los ejemplos anteriores compilados con transiciones de vista.
En esta primera demostración, en lugar de configurar @starting-style
y otras transformaciones de CSS, las transiciones de vistas se encargarán de realizarlas. La transición de vista se configura de la siguiente manera:
Primero, en CSS, asigna a cada tarjeta un view-transition-name
individual.
.card-1 {
view-transition-name: card-1;
}
.card-2 {
view-transition-name: card-2;
}
/* etc. */
Luego, en JavaScript, une la mutación del DOM (en este caso, quita la tarjeta) en una transición de vista.
deleteBtn.addEventListener('click', () => {
// Check for browser support
if (document.startViewTransition) {
document.startViewTransition(() => {
// DOM mutation
card.remove();
});
}
// Alternative if no browser support
else {
card.remove();
}
})
Ahora, el navegador puede controlar el fundido de salida y la transformación de cada tarjeta a su nueva posición.
Esto también puede resultar útil en la demostración para agregar o quitar elementos de una lista. En este caso, deberás recordar agregar un view-transition-name
único para cada tarjeta creada.
Conclusión
Estas nuevas funciones de la plataforma nos acercan un paso más a las animaciones de entrada y salida fluidas en la plataforma web. Para obtener más información, consulta estos vínculos: