Me encantan los pequeños detalles que hacen que un sitio web se sienta como algo más que un documento estático. ¿Qué pasa si el contenido web no “aparece” simplemente cuando se carga una página, sino que aparece, se desliza, se desvanece o gira en su lugar? Podría ser exagerado decir que movimientos como este siempre son útiles, aunque en algunos casos pueden llamar la atención sobre ciertos elementos, reforzar qué elementos son distintos entre sí o incluso indicar un cambio de estado. Entonces, tampoco son totalmente inútiles.
Entonces, reuní un conjunto de utilidades CSS para animar elementos a medida que entran a la vista. Y sí, este CSS puro. No solo tiene una buena variedad de animaciones y variaciones, sino que también admite escalonar esas animaciones, casi como una forma de crear escenas.
Ya sabes, cosas como esta:
Lo que en realidad es solo una versión más elegante de esto:
Primero repasaremos la base que usé para crear las animaciones, luego veremos las pequeñas florituras que agregué, cómo escalonar las animaciones, luego cómo aplicarlas a los elementos HTML antes de ver también cómo hacer todo esto. respetando las preferencias de movimiento reducidas del usuario.
Los basicos
La idea central consiste en agregar un CSS simple @keyframes
animación que se aplica a todo lo que queremos animar al cargar la página. Hagamos que un elemento se desvanezca, pasando de opacity: 0
a opacity: 1
en medio segundo:
.animate {
animation-duration: 0.5s;
animation-name: animate-fade;
animation-delay: 0.5s;
animation-fill-mode: backwards;
}
@keyframes animate-fade {
0% { opacity: 0; }
100% { opacity: 1; }
}
Observe también que hay un animation-delay
de medio segundo allí, lo que permite que el resto del sitio se cargue primero. El animation-fill-mode: backwards
está ahí para asegurarnos de que nuestro estado de animación inicial esté activo en la carga de la página. Sin esto, nuestro elemento animado aparece a la vista antes de que lo deseemos.
Si somos perezosos, podemos dejarlo todo y seguir con esto. Pero, los lectores de Programar Plusno son perezosos, por supuesto, así que veamos cómo podemos mejorar este tipo de cosas con un sistema.
Animaciones más sofisticadas
Es mucho más divertido tener una variedad de animaciones con las que trabajar que solo una o dos. Ni siquiera necesitamos crear un montón de nuevos @keyframes
para hacer más animaciones. Es bastante simple crear nuevas clases en las que todo lo que cambiamos es qué fotogramas usa la animación, manteniendo todos los tiempos iguales.
Hay casi una cantidad infinita de animaciones CSS por ahí. (Ver animate.style para una gran colección). Filtros CSS, como blur()
, brightness()
y saturate()
y, por supuesto, las transformaciones CSS también se pueden utilizar para crear aún más variaciones.
Pero por ahora, comencemos con una nueva clase de animación que usa una transformación CSS para hacer que un elemento “destaque” en su lugar.
.animate.pop {
animation-duration: 0.5s;
animation-name: animate-pop;
animation-timing-function: cubic-bezier(.26, .53, .74, 1.48);
}
@keyframes animate-pop {
0% {
opacity: 0;
transform: scale(0.5, 0.5);
}
100% {
opacity: 1;
transform: scale(1, 1);
}
}
Arrojé un poco cubic-bezier()
curva de tiempo, cortesía de cubic-bezier.com indispensable de Lea Verou para un rebote elástico.
Agregar retrasos
¡Podemos hacerlo mejor! Por ejemplo, podemos animar elementos para que entren en diferentes momentos. Esto crea un escalonamiento que genera un movimiento de apariencia compleja sin una cantidad compleja de código.
Esta animación en tres elementos de página usando un filtro CSS, transformación CSS y escalonada alrededor de una décima de segundo cada uno, se siente realmente bien:
Todo lo que hicimos fue crear una nueva clase para cada elemento que se espacia cuando los elementos comienzan a animarse, usando animation-delay
valores que están separados por una décima de segundo.
.delay-1 { animation-delay: 0.6s; }
.delay-2 { animation-delay: 0.7s; }
.delay-3 { animation-delay: 0.8s; }
Todo lo demás es exactamente igual. Y recuerda que nuestra demora base es 0.5s
, por lo que estas clases auxiliares cuentan a partir de ahí.
Respetando las preferencias de accesibilidad
Seamos buenos ciudadanos de la web y eliminemos nuestras animaciones para los usuarios que han habilitado su configuración de preferencia de movimiento reducido:
@media screen and (prefers-reduced-motion: reduce) {
.animate { animation: none !important; }
}
De esta forma, la animación nunca se carga y los elementos entran a la vista como de costumbre. Sin embargo, es aquí donde vale la pena recordar que el movimiento “reducido” no siempre significa el movimiento de “remoción”.
Aplicar animaciones a elementos HTML
Hasta ahora, hemos visto una animación básica, así como una un poco más elegante que pudimos hacer aún más elegante con retrasos de animación escalonados que se encuentran en las nuevas clases. También vimos cómo podemos respetar las preferencias de movimiento del usuario al mismo tiempo.
Aunque hay demostraciones en vivo que muestran los conceptos, en realidad no hemos analizado cómo aplicar nuestro trabajo a HTML. Y lo que es genial es que podemos usar esto en casi cualquier elemento, ya sea div, span, artículo, encabezado, sección, tabla, formulario … ya entiendes la idea.
Esto es lo que haremos. Queremos usar nuestro sistema de animación en tres elementos HTML donde cada elemento obtiene tres clases. Podríamos codificar todo el código de animación para el elemento en sí, pero dividirlo nos da un pequeño sistema de animación que podemos reutilizar.
.animate
: Esta es la clase base que contiene nuestra declaración y tiempo de animación principal.- El tipo de animación: Usaremos nuestra animación “pop” de antes, pero también podríamos usar la que se desvanece. Esta clase es técnicamente opcional pero es una buena forma de aplicar distintos movimientos.
.delay-<number>
: Como vimos anteriormente, podemos crear clases distintas que se utilizan para escalonar cuando comienza la animación en cada elemento, lo que crea un efecto nítido. Esta clase también es opcional.
Entonces, nuestros elementos animados ahora podrían verse así:
<h2 class="animate pop">One!</h2>
<h2 class="animate pop delay-1">Two!</h2>
<h2 class="animate pop delay-2">Three!</h2>
¡Contémoslos!
Conclusión
Mira eso: comenzamos con un conjunto aparentemente básico de @keyframes
y lo convirtió en un sistema completo para aplicar animaciones interesantes para los elementos que entran a la vista.
Esto es ridículamente divertido, por supuesto. Pero la gran conclusión para mí es cómo los ejemplos que miramos forman un sistema completo que se puede usar para crear una línea de base, diferentes tipos de animaciones, retrasos escalonados y un enfoque para respetar las preferencias de movimiento del usuario. Para mí, estos son todos los ingredientes de un sistema flexible que es fácil de usar. Nos da mucho con un poco, sin mucho dinero extra.
Lo que cubrimos podría ser una biblioteca de animación completa. Pero, por supuesto, no me detuve ahí. Tengo todo mi archivo CSS de animaciones en todo su esplendor para ti. Hay varios tipos más de animaciones allí, incluidas 15 clases de retrasos diferentes que se pueden usar para cosas asombrosas. Los he estado usando en mis propios proyectos, pero todavía es un borrador inicial y me encantaría recibir comentarios al respecto. ¡Disfruta y déjame saber lo que piensas en los comentarios!
/* ==========================================================================
Animation System by Neale Van Fleet from Rogue Amoeba
========================================================================== */
.animate {
animation-duration: 0.75s;
animation-delay: 0.5s;
animation-name: animate-fade;
animation-timing-function: cubic-bezier(.26, .53, .74, 1.48);
animation-fill-mode: backwards;
}
/* Fade In */
.animate.fade {
animation-name: animate-fade;
animation-timing-function: ease;
}
@keyframes animate-fade {
0% { opacity: 0; }
100% { opacity: 1; }
}
/* Pop In */
.animate.pop { animation-name: animate-pop; }
@keyframes animate-pop {
0% {
opacity: 0;
transform: scale(0.5, 0.5);
}
100% {
opacity: 1;
transform: scale(1, 1);
}
}
/* Blur In */
.animate.blur {
animation-name: animate-blur;
animation-timing-function: ease;
}
@keyframes animate-blur {
0% {
opacity: 0;
filter: blur(15px);
}
100% {
opacity: 1;
filter: blur(0px);
}
}
/* Glow In */
.animate.glow {
animation-name: animate-glow;
animation-timing-function: ease;
}
@keyframes animate-glow {
0% {
opacity: 0;
filter: brightness(3) saturate(3);
transform: scale(0.8, 0.8);
}
100% {
opacity: 1;
filter: brightness(1) saturate(1);
transform: scale(1, 1);
}
}
/* Grow In */
.animate.grow { animation-name: animate-grow; }
@keyframes animate-grow {
0% {
opacity: 0;
transform: scale(1, 0);
visibility: hidden;
}
100% {
opacity: 1;
transform: scale(1, 1);
}
}
/* Splat In */
.animate.splat { animation-name: animate-splat; }
@keyframes animate-splat {
0% {
opacity: 0;
transform: scale(0, 0) rotate(20deg) translate(0, -30px);
}
70% {
opacity: 1;
transform: scale(1.1, 1.1) rotate(15deg);
}
85% {
opacity: 1;
transform: scale(1.1, 1.1) rotate(15deg) translate(0, -10px);
}
100% {
opacity: 1;
transform: scale(1, 1) rotate(0) translate(0, 0);
}
}
/* Roll In */
.animate.roll { animation-name: animate-roll; }
@keyframes animate-roll {
0% {
opacity: 0;
transform: scale(0, 0) rotate(360deg);
}
100% {
opacity: 1;
transform: scale(1, 1) rotate(0deg);
}
}
/* Flip In */
.animate.flip {
animation-name: animate-flip;
transform-style: preserve-3d;
perspective: 1000px;
}
@keyframes animate-flip {
0% {
opacity: 0;
transform: rotateX(-120deg) scale(0.9, 0.9);
}
100% {
opacity: 1;
transform: rotateX(0deg) scale(1, 1);
}
}
/* Spin In */
.animate.spin {
animation-name: animate-spin;
transform-style: preserve-3d;
perspective: 1000px;
}
@keyframes animate-spin {
0% {
opacity: 0;
transform: rotateY(-120deg) scale(0.9, .9);
}
100% {
opacity: 1;
transform: rotateY(0deg) scale(1, 1);
}
}
/* Slide In */
.animate.slide { animation-name: animate-slide; }
@keyframes animate-slide {
0% {
opacity: 0;
transform: translate(0, 20px);
}
100% {
opacity: 1;
transform: translate(0, 0);
}
}
/* Drop In */
.animate.drop {
animation-name: animate-drop;
animation-timing-function: cubic-bezier(.77, .14, .91, 1.25);
}
@keyframes animate-drop {
0% {
opacity: 0;
transform: translate(0,-300px) scale(0.9, 1.1);
}
95% {
opacity: 1;
transform: translate(0, 0) scale(0.9, 1.1);
}
96% {
opacity: 1;
transform: translate(10px, 0) scale(1.2, 0.9);
}
97% {
opacity: 1;
transform: translate(-10px, 0) scale(1.2, 0.9);
}
98% {
opacity: 1;
transform: translate(5px, 0) scale(1.1, 0.9);
}
99% {
opacity: 1;
transform: translate(-5px, 0) scale(1.1, 0.9);
}
100% {
opacity: 1;
transform: translate(0, 0) scale(1, 1);
}
}
/* Animation Delays */
.delay-1 {
animation-delay: 0.6s;
}
.delay-2 {
animation-delay: 0.7s;
}
.delay-3 {
animation-delay: 0.8s;
}
.delay-4 {
animation-delay: 0.9s;
}
.delay-5 {
animation-delay: 1s;
}
.delay-6 {
animation-delay: 1.1s;
}
.delay-7 {
animation-delay: 1.2s;
}
.delay-8 {
animation-delay: 1.3s;
}
.delay-9 {
animation-delay: 1.4s;
}
.delay-10 {
animation-delay: 1.5s;
}
.delay-11 {
animation-delay: 1.6s;
}
.delay-12 {
animation-delay: 1.7s;
}
.delay-13 {
animation-delay: 1.8s;
}
.delay-14 {
animation-delay: 1.9s;
}
.delay-15 {
animation-delay: 2s;
}
@media screen and (prefers-reduced-motion: reduce) {
.animate {
animation: none !important;
}
}