Diferentes enfoques para la creación de una animación escalonada | Programar Plus

Animar elementos, en su forma más básica, es bastante sencillo. Defina los fotogramas clave. Nombra la animación. Llámalo en un elemento.

Pero a veces necesitamos algo un poco más complejo para tener la “sensación” correcta de cómo se mueven las cosas. Por ejemplo, un ecualizador de sonido puede usar la misma animación en cada barra, pero están escalonados para dar la ilusión de estar animados de forma independiente.

Ver la pluma
Ecualizador de sonido de Apple Music en SVG por Geoff Graham (@geoffgraham)
en CodePen.

Recientemente estaba construyendo un tablero y quería que los elementos de uno de los widgets aparecieran con una animación escalonada.

Al igual que el ecualizador de sonido de arriba, comencé a bajar el :nth-child ruta. Utilicé la lista desordenada<ul>) como contenedor principal, le dio una clase y empleó el :nth-child pseudo selector para compensar cada elemento de la lista con animaton-delay.

.my-list li {
  animation: my-animation 300ms ease-out;
}

.my-list li:nth-child(1) {
  animation-delay: 100ms;
}

.my-list li:nth-child(2) {
  animation-delay: 200ms;
}

.my-list li:nth-child(3) {
  animation-delay: 300ms;
}

/* and so on */

De hecho, esta técnica escalona bien los elementos, especialmente si sabe cuántos elementos van a estar en la lista en un momento dado. Sin embargo, donde las cosas se desmoronan es cuando la cantidad de elementos es impredecible, que fue el caso del widget que estaba construyendo para el tablero. Realmente no quería volver a este fragmento de código cada vez que cambiaba la cantidad de elementos en la lista, así que eliminé un bucle Sass rápido que representa hasta 50 elementos e incrementa el retraso de la animación con cada elemento:

.my-list {
  li {
    animation: my-animation 300ms ease-out;
      
    @for $i from 1 through 50 {
      &:nth-child(#{$i}) {
        animation-delay: 100ms * $i;
      }
    }
  }
}

¡Deberias hacer eso! Sin embargo, se siente demasiado hack. Claro, no agrega mucho peso al archivo, pero sabe que el CSS compilado incluirá un montón de selectores no utilizados, como nth-child(45).

Debe haber una mejor manera. Aquí es donde normalmente recurriría a JavaScript para encontrar todos los elementos y agregar un retraso, pero … esta vez dediqué un poco de tiempo a explorar para ver si hay una manera de hacerlo solo con CSS.

¿Qué hay de los contadores CSS?

Lo primero que pensé fue usar un contador CSS en combinación con el calc() función:

.my-list {
  counter-reset: my-counter;
}

.my-list li {
  counter-increment: my-counter;
  animation-delay: calc(counter(my-counter) * 100ms);
}

Desafortunadamente, eso no funcionará porque la especificación dice que los contadores no se pueden usar en calc()):

Componentes de un calc() La expresión puede ser valores literales o attr() o calc() Expresiones

Resulta que a algunas personas les gusta esta idea, pero no ha ido más allá de la etapa de borrador.

¿Qué tal un atributo de datos?

Habiendo leído ese extracto de la especificación, aprendí que calc() puedo usar attr(). Y, de acuerdo con la especificación de valores y unidades de CSS):

En CSS3, el attr() la expresión puede devolver muchos tipos diferentes

Esto me hizo pensar; quizás un atributo de datos podría hacer el truco.

<ul class="my-list">
  <li data-count="1"></li>
  <li data-count="2"></li>
  <li data-count="3"></li>
  <li data-count="4"></li>
</ul>
.my-list li {
  animation-delay: calc(attr(data-count) * 150ms);
}

¡Pero mis esperanzas se desvanecieron ya que el soporte del navegador para esto es diabólico!

Estos datos de soporte del navegador son de Caniuse, que tiene más detalles. Un número indica que el navegador admite la función en esa versión y posteriores.

Escritorio

Cromo Firefox ES DECIR Borde Safari
No No No No No

Móvil / Tableta

Android Chrome Android Firefox Androide Safari de iOS
No No No No

Entonces, volvamos a la mesa de dibujo.

¿Qué hay de las propiedades personalizadas?

La siguiente idea que tuve fue usar propiedades personalizadas de CSS. No es bonito, pero funcionó 🙂

Ver la pluma
Orden de animación de variables CSS por Dan Benmore (@dbenmore)
en CodePen.

Resulta que también es bastante flexible. Por ejemplo, la animación se puede invertir:

Ver la pluma
Variables CSS orden de animación inversa por Dan Benmore (@dbenmore)
en CodePen.

También puede hacer algo completamente aleatorio y animar elementos al mismo tiempo:

Ver la pluma
Orden de animación aleatoria de variables CSS por Dan Benmore (@dbenmore)
en CodePen.

Incluso podemos empujarlo un poco más y hacer un swoosh diagonal:

Ver la pluma
Establecer escalonamiento de animación con propiedades / variables CSS por Dan Benmore (@dbenmore)
en CodePen.

El soporte del navegador no es tan malo (los golpes se quedan en Internet Explorer).

Estos datos de soporte del navegador son de Caniuse, que tiene más detalles. Un número indica que el navegador admite la función en esa versión en adelante.

Escritorio

Cromo Firefox ES DECIR Borde Safari
49 31 No dieciséis 10

Móvil / Tableta

Android Chrome Android Firefox Androide Safari de iOS
96 95 96 10.0-10.2

Una de las grandes características de CSS es que ignorará cosas que no comprenda, gracias a la cascada. Eso significa que todo se animará a la vista juntos. Si ese no es su bolso, puede agregar una consulta de función para anular una animación predeterminada:

.my-list li {
  animation: fallback-animation;
}

@supports (--variables) {
  .my-list li {
    animation: fancy-animation;
    animation-delay: calc(var(--animation-order) * 100ms);
  }
}

Vanilla CSS FTW

Cuanto más me detengo y me pregunto si necesito JavaScript, más me sorprende lo que CSS puede hacer por sí solo. Claro, sería bueno si los contadores CSS pudieran usarse en un calc() función y sería una solución bastante elegante. Pero por ahora, las propiedades personalizadas en línea brindan una manera poderosa y flexible de resolver este problema.

(Visited 10 times, 1 visits today)