Retraso de la animación CSS en la repetición

81

Recientemente descubrí cómo usar "correctamente" las animaciones CSS (anteriormente las descarté por no poder hacer secuencias complejas como lo haría en JavaScript). Así que ahora estoy aprendiendo sobre ellos.

Para este efecto, estoy tratando de tener un "destello" de degradado que recorra un elemento similar a una barra de progreso. Similar al efecto en las barras de progreso nativas de Windows Vista / 7.

@keyframes barshine {
  from {background-image:linear-gradient(120deg,rgba(255,255,255,0) -10%,rgba(255,255,255,0.25) -5%,rgba(255,255,255,0) 0%);}
  to {background-image:linear-gradient(120deg,rgba(255,255,255,0) 100%,rgba(255,255,255,0.25) 105%,rgba(255,255,255,0) 110%);}
}
.progbar {
  animation: barshine 1s 4s linear infinite;
}

Como puede ver, estoy tratando de tener un retraso de 4 segundos, seguido por el brillo que se extiende en 1 segundo, repetido.

Sin embargo, parece que animation-delaysolo se aplica a la primera iteración, después de la cual el brillo sigue barriendo repetidamente.

"Resolví" este problema de la siguiente manera:

@keyframes expbarshine {
  from {background-image:linear-gradient(120deg,rgba(255,255,255,0) -10%,rgba(255,255,255,0.25) -5%,rgba(255,255,255,0) 0%);}
  80% {background-image:linear-gradient(120deg,rgba(255,255,255,0) -10%,rgba(255,255,255,0.25) -5%,rgba(255,255,255,0) 0%);}
  to {background-image:linear-gradient(120deg,rgba(255,255,255,0) 100%,rgba(255,255,255,0.25) 105%,rgba(255,255,255,0) 110%);}
}
.progbar {
  animation: barshine 5s linear infinite;
}

fromy 80%son exactamente iguales, lo que da como resultado un "retraso" del 80% de la duración de la animación.

Esto funciona, pero para mi próxima animación, necesito que el retraso sea variable (constante para un elemento en particular, pero variable entre los elementos que usan la animación), mientras que la animación en sí permanece exactamente con la misma duración.

Con la "solución" anterior, terminaría con una animación más lenta cuando todo lo que quiero es un retraso más largo.

¿Es posible animation-delayaplicarlo a todas las iteraciones, en lugar de solo a la primera?

Niet the Dark Absol
fuente
Lamentablemente no. animation-delayes el retraso antes de que comience la animación, y no hay otra propiedad como esta. Hay una mala solución con JavaScript que probablemente preferiría no usar :)
Ry-

Respuestas:

55

Tuve un problema similar y usé

@-webkit-keyframes pan {
   0%, 10%       { -webkit-transform: translate3d( 0%, 0px, 0px); }
   90%, 100%     { -webkit-transform: translate3d(-50%, 0px, 0px); }
}

Es un poco irritante que tengas que fingir tu duración para tener en cuenta los 'retrasos' en ambos extremos.

Sebastián Thomas
fuente
18

minitech tiene razón en eso animation-delayespecifica el retraso antes de que comience la animación y NO el retraso entre iteraciones. El borrador de la especificación de los editores lo describe bien y hubo una discusión sobre esta característica que está describiendo aquí, lo que sugiere esta característica de retraso de iteración.

Si bien puede haber una solución en JS, puede simular este retraso de iteración para el destello de la barra de progreso utilizando solo CSS.

Al declarar el div flare position:absolutey el div principal overflow: hidden, establecer el 100% del estado del fotograma clave mayor que el ancho de la barra de progreso y jugar con la función de tiempo cúbico-bezier y los valores de desplazamiento izquierdo, puede emular un tiempo ease-in-outo linearcon un retraso".

Sería interesante escribir un mixin less / scss para calcular exactamente el desplazamiento izquierdo y la función de sincronización para obtener esto exactamente, pero no tengo tiempo en este momento para jugar con él. ¡Me encantaría ver algo así!

Aquí hay una demostración que hice para mostrar esto. (Traté de emular la barra de progreso de Windows 7 y me quedé un poco corto, pero demuestra de lo que estoy hablando)

Demostración: http://codepen.io/timothyasp/full/HlzGu

<!-- HTML -->
<div class="bar">
   <div class="progress">
      <div class="flare"></div>
   </div>
</div>


/* CSS */

@keyframes progress {
  from {
    width: 0px;
  }
  to {
    width: 600px;
  }
}

@keyframes barshine {
  0% {
    left: -100px;
  }

  100% {
    left: 1000px;
  }
}
.flare {
  animation-name: barshine;
  animation-duration: 3s;
  animation-direction: normal;
  animation-fill-mode: forwards;
  animation-timing-function: cubic-bezier(.14, .75, .2, 1.01);
  animation-iteration-count: infinite;
  left: 0;
  top: 0;
  height: 40px;
  width: 100px;
  position: absolute;
  background: -moz-radial-gradient(center, ellipse cover,  rgba(255,255,255,0.69) 0%, rgba(255,255,255,0) 87%); /* FF3.6+ */
  background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%,rgba(255,255,255,0.69)), color-stop(87%,rgba(255,255,255,0))); /* Chrome,Safari4+ */
  background: -webkit-radial-gradient(center, ellipse cover,  rgba(255,255,255,0.69) 0%,rgba(255,255,255,0) 87%); /* Chrome10+,Safari5.1+ */
  background: -o-radial-gradient(center, ellipse cover,  rgba(255,255,255,0.69) 0%,rgba(255,255,255,0) 87%); /* Opera 12+ */
  background: -ms-radial-gradient(center, ellipse cover,  rgba(255,255,255,0.69) 0%,rgba(255,255,255,0) 87%); /* IE10+ */
  background: radial-gradient(ellipse at center,  rgba(255,255,255,0.69) 0%,rgba(255,255,255,0) 87%); /* W3C */
  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#b0ffffff', endColorstr='#00ffffff',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */
  z-index: 10;
}
.progress {
  animation-name: progress;
  animation-duration: 10s;
  animation-delay: 1s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  overflow: hidden;
  position:relative;
  z-index: 1;
  height: 100%;
  width: 100%;
  border-right: 1px solid #0f9116;
  background: #caf7ce; /* Old browsers */
  background: -moz-linear-gradient(top, #caf7ce 0%, #caf7ce 18%, #3fe81e 45%, #2ab22a 96%); /* FF3.6+ */
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#caf7ce), color-stop(18%,#caf7ce), color-stop(45%,#3fe81e), color-stop(96%,#2ab22a)); /* Chrome,Safari4+ */
  background: -webkit-linear-gradient(top, #caf7ce 0%,#caf7ce 18%,#3fe81e 45%,#2ab22a 96%); /* Chrome10+,Safari5.1+ */
  background: -o-linear-gradient(top, #caf7ce 0%,#caf7ce 18%,#3fe81e 45%,#2ab22a 96%); /* Opera 11.10+ */
  background: -ms-linear-gradient(top, #caf7ce 0%,#caf7ce 18%,#3fe81e 45%,#2ab22a 96%); /* IE10+ */
  background: linear-gradient(to bottom, #caf7ce 0%,#caf7ce 18%,#3fe81e 45%,#2ab22a 96%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#caf7ce', endColorstr='#2ab22a',GradientType=0 ); /* IE6-9 */
}

.progress:after {
  content: "";
  width: 100%;
  height: 29px;
  right: 0;
  bottom: 0;
  position: absolute;
  z-index: 3;
  background: -moz-linear-gradient(left, rgba(202,247,206,0) 0%, rgba(42,178,42,1) 100%); /* FF3.6+ */
  background: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(202,247,206,0)), color-stop(100%,rgba(42,178,42,1))); /* Chrome,Safari4+ */
  background: -webkit-linear-gradient(left, rgba(202,247,206,0) 0%,rgba(42,178,42,1) 100%); /* Chrome10+,Safari5.1+ */
  background: -o-linear-gradient(left, rgba(202,247,206,0) 0%,rgba(42,178,42,1) 100%); /* Opera 11.10+ */
  background: -ms-linear-gradient(left, rgba(202,247,206,0) 0%,rgba(42,178,42,1) 100%); /* IE10+ */
  background: linear-gradient(to right, rgba(202,247,206,0) 0%,rgba(42,178,42,1) 100%); /* W3C */
  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00caf7ce', endColorstr='#2ab22a',GradientType=1 ); /* IE6-9 */
}

.bar {
  margin-top: 30px;
  height: 40px;
  width: 600px;
  position: relative;
  border: 1px solid #777;
  border-radius: 3px;
}
tim
fuente
46
CSS típico. Proporcionan animaciones CSS, por lo que no se hace en Javascript, y el estilo está todo en un solo lugar, pero luego, si desea hacer algo más que lo básico, debe implementar un laberinto de hacks. ¿Por qué no implementan cosas que faciliten las cosas a los desarrolladores?
Jonathan.
10

Esto es lo que debes hacer. Debería funcionar porque tiene una animación de 1 segundo, luego un retraso de 4 segundos entre iteraciones:

@keyframes barshine {
  0% {
  background-image:linear-gradient(120deg,rgba(255,255,255,0) 0%,rgba(255,255,255,0.25) -5%,rgba(255,255,255,0) 0%);
  }
  20% {
    background-image:linear-gradient(120deg,rgba(255,255,255,0) 10%,rgba(255,255,255,0.25) 105%,rgba(255,255,255,0) 110%);
  }
}
.progbar {
  animation: barshine 5s 0s linear infinite;
}

Así que he estado jugando mucho con esto y puedes hacerlo sin ser muy hacker. Esta es la forma más sencilla de poner un retraso entre las iteraciones de la animación que es 1. SUPER FÁCIL y 2. solo requiere un poco de lógica. Mira esta animación de baile que hice:

.dance{
  animation-name: dance;
  -webkit-animation-name: dance;

  animation-iteration-count: infinite;
  -webkit-animation-iteration-count: infinite;
  animation-duration: 2.5s;
  -webkit-animation-duration: 2.5s;

  -webkit-animation-delay: 2.5s;
  animation-delay: 2.5s;
  animation-timing-function: ease-in;
  -webkit-animation-timing-function: ease-in;

}
@keyframes dance {
  0% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  25% {
    -webkit-transform: rotate(-120deg);
    -moz-transform: rotate(-120deg);
    -o-transform: rotate(-120deg);
    -ms-transform: rotate(-120deg);
    transform: rotate(-120deg);
  }
  50% {
    -webkit-transform: rotate(20deg);
    -moz-transform: rotate(20deg);
    -o-transform: rotate(20deg);
    -ms-transform: rotate(20deg);
    transform: rotate(20deg);
  }
  100% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    transform: rotate(0deg);
  }
}

@-webkit-keyframes dance {
  0% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  20% {
    -webkit-transform: rotate(20deg);
    -moz-transform: rotate(20deg);
    -o-transform: rotate(20deg);
    -ms-transform: rotate(20deg);
    transform: rotate(20deg);
  }
  40% {
    -webkit-transform: rotate(-120deg);
    -moz-transform: rotate(-120deg);
    -o-transform: rotate(-120deg);
    -ms-transform: rotate(-120deg);
    transform: rotate(-120deg);
  }
  60% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  80% {
    -webkit-transform: rotate(-120deg);
    -moz-transform: rotate(-120deg);
    -o-transform: rotate(-120deg);
    -ms-transform: rotate(-120deg);
    transform: rotate(-120deg);
  }
  95% {
    -webkit-transform: rotate(20deg);
    -moz-transform: rotate(20deg);
    -o-transform: rotate(20deg);
    -ms-transform: rotate(20deg);
    transform: rotate(20deg);
  }
}

De hecho, vine aquí tratando de averiguar cómo poner un retraso en la animación, cuando me di cuenta de que solo 1. extiendes la duración de la animación y la proporción de tiempo para cada animación. Antes de que los tuviera cada uno con una duración de 0,5 segundos durante un total de 2,5 segundos. Ahora digamos que quería agregar un retraso igual a la duración total, por lo que un retraso de 2,5 segundos.

El tiempo de animación es de 2,5 segundos y el retraso es de 2,5, por lo que cambia la duración a 5 segundos. Sin embargo, debido a que duplicó la duración total, querrá reducir a la mitad la proporción de animaciones. Consulta la final a continuación. Esto funcionó perfectamente para mí.

@-webkit-keyframes dance {
  0% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  10% {
    -webkit-transform: rotate(20deg);
    -moz-transform: rotate(20deg);
    -o-transform: rotate(20deg);
    -ms-transform: rotate(20deg);
    transform: rotate(20deg);
  }
  20% {
    -webkit-transform: rotate(-120deg);
    -moz-transform: rotate(-120deg);
    -o-transform: rotate(-120deg);
    -ms-transform: rotate(-120deg);
    transform: rotate(-120deg);
  }
  30% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  40% {
    -webkit-transform: rotate(-120deg);
    -moz-transform: rotate(-120deg);
    -o-transform: rotate(-120deg);
    -ms-transform: rotate(-120deg);
    transform: rotate(-120deg);
  }
  50% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    transform: rotate(0deg);
  }
}

En suma:

Estos son los cálculos que probablemente usaría para descubrir cómo cambiar la duración de la animación y el% de cada parte.

duración_deseada = x

deseada_duration = animation_part_duration1 + animation_part_duration2 + ... (y así sucesivamente)

delay_delay = y

duración total = x + y

animation_part_duration1_actual = animation_part_duration1 * deseada_duration / total_duration

HabladorÁrbol
fuente
francés manchado :) (yo también soy francés, no te preocupes)
julesbou
5

Prefiero escribir un poco de JavaScript que hacer que CSS sea menos manejable.

Primero, solo aplique la animación CSS en un cambio de atributo de datos:

.progbar[data-animation="barshine"] {
    animation: barshine 1s linear;
}

Luego agregue javascript para alternar la animación a la mitad de la cantidad de retraso.

var progbar = document.querySelector('.progbar');
var on = false;

setInterval(function () {
    progbar.setAttribute('data-animation', (on) ? 'barshine' : '');
    on = !on;
}, 3000);

O si no desea que la animación se ejecute cuando la pestaña está oculta:

var progbar = document.querySelector('.progbar');
var on = false;

var update = function () {
    progbar.setAttribute('data-animation', (on) ? 'barshine' : '');
    on = !on;
    setTimer();
};

var setTimer = function () {
    setTimeout(function () {
        requestAnimationFrame(update);
    }, 3000);
};

setTimer();
cuth
fuente
2

Hice un cartel en la pared que se mueve de izquierda a derecha con intervalos. Para mi funciona:

.div-animation {
   -webkit-animation: bounce 2000ms ease-out;
    -moz-animation: bounce 2000ms ease-out;
    -o-animation: bounce 2000ms ease-out;
    animation: bounce 2000ms ease-out infinite;
    -webkit-animation-delay: 2s; /* Chrome, Safari, Opera */
    animation-delay: 2s;
    transform-origin: 55% 10%;    
}

@-webkit-keyframes bounce {
    0% {
        transform: rotate(0deg);
    }
    3% {
        transform: rotate(1deg);
    }
    6% {
        transform: rotate(2deg);
    }
    9% {
        transform: rotate(3deg);
    }
    12% {
        transform: rotate(2deg);
    }
    15% {
        transform: rotate(1deg);
    }
    18% {
        transform: rotate(0deg);
    }
    21% {
        transform: rotate(-1deg);
    }
    24% {
        transform: rotate(-2deg);
    }
    27% {
        transform: rotate(-3deg);
    }
    30% {
        transform: rotate(-2deg);
    }
    33% {
        transform: rotate(-1deg);
    }
    36% {
        transform: rotate(0deg);
    }
    100% {
        transform: rotate(0deg);
    }
}
Bubas
fuente
2

Otra forma de lograr una pausa entre animaciones es aplicar una segunda animación que oculte el elemento por la cantidad de retraso que desee. Esto tiene la ventaja de permitirle utilizar una función de suavizado CSS como lo haría normalmente.

.star {
  animation: shooting-star 1000ms ease-in-out infinite,
    delay-animation 2000ms linear infinite;
}

@keyframes shooting-star {
  0% {
    transform: translate(0, 0) rotate(45deg);
  }

  100% {
    transform: translate(300px, 300px) rotate(45deg);
  }
}

@keyframes delay-animation {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 1;
  }
  50.01% {
    opacity: 0;
  }
  100% {
    opacity: 0;
  }
}

Esto solo funciona si desea que el retraso sea un múltiplo de la duración de la animación. Usé esto para hacer que una lluvia de estrellas fugaces pareciera más aleatoria: https://codepen.io/ericdjohnson/pen/GRpOgVO

Eric Johnson
fuente
1

Aquí hay un pequeño fragmento que muestra lo mismo durante el 75% del tiempo, luego se desliza. Este esquema de repetición emula muy bien el retraso:

@-webkit-keyframes slide    {
0%   {background-position: 0 0;}
25%  {background-position: 0 0;}
50%  {background-position: 0 0;}
75%  {background-position: 0 0;}
100% {background-position: 13em 0;}
}

@-moz-keyframes slide       {
0%   {background-position: 0 0;}
25%  {background-position: 0 0;}
50%  {background-position: 0 0;}
75%  {background-position: 0 0;}
100% {background-position: 13em 0;}
}

@keyframes slide            {
0%   {background-position: 0 0;}
25%  {background-position: 0 0;}
50%  {background-position: 0 0;}
75%  {background-position: 0 0;}
100% {background-position: 13em 0;}
}
no mires
fuente
0

El retraso es posible solo una vez al principio con infinito. en sort delay no funciona con bucle infinito. para eso tienes que mantener los espacios en blanco de animación de fotogramas clave.

@-webkit-keyframes barshine {
  10% {background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#1e5799), color-stop(100%,#7db9e8));
    }
  60% {background: -webkit-linear-gradient(top, #7db9e8 0%,#d32a2d 100%);}
}

animará entre un 10% y un 60% y esperará a completar un 40% más. Entonces el 40% viene en retraso.

encontrar un ejemplo de violín

Ganesh Yadav
fuente
0

Sé que esto es antiguo, pero estaba buscando la respuesta en esta publicación y con jquery puedes hacerlo fácilmente y sin demasiados problemas. Simplemente declare su fotograma clave de animación en el CSS y configure la clase con los atributos que le gustaría. En mi caso, utilicé la animación tada de css animate:

.tada {
    -webkit-animation-name: tada;
    animation-name: tada;
    -webkit-animation-duration: 1.25s;
    animation-duration: 1.25s;
    -webkit-animation-fill-mode: both;
    animation-fill-mode: both;
}

Quería que la animación se ejecutara cada 10 segundos, por lo que jquery solo agrega la clase, después de 6000 ms (tiempo suficiente para que termine la animación) elimina la clase y 4 segundos después agrega la clase nuevamente y la animación comienza nuevamente.

$(document).ready(function() {
  setInterval(function() {

    $(".bottom h2").addClass("tada");//adds the class

    setTimeout(function() {//waits 6 seconds to remove the class
      $(".bottom h2").removeClass("tada");
    }, 6000);

  }, 10000)//repeats the process every 10 seconds
});

No es nada difícil como publicó un chico.

Marcos Silva Lepe
fuente
No estoy seguro de por qué usarías jQuery para .classList.add("tada"): D
Niet the Dark Absol
Supongo que es más fácil de recordar ... y no tienes que usar jquery en absoluto, puedes escribir 3 líneas de javascript si quieres en lugar de solo 1 con jquery, depende totalmente de la persona que escribe el código :)
Marcos Silva Lepe
No lo sé, $(".bottom h2").addClass("tada")y document.querySelector(".bottom h2").classList.add("tada")son tan similares que no vale la pena cargar / ejecutar el código jQuery: p
Niet the Dark Absol
Supongo que tienes razón en eso. Vi este control deslizante realmente genial en el front-end gratuito que usa javascript y, dado que uso principalmente jquery, intenté replicar el control deslizante con él, lo cual hice, pero toma como 5 veces los recursos del control deslizante original hecho con javascript :( Supongo que Javascript es mucho más ligero que el uso de código de jQuery, por otro lado, es menos detallado
Marcos Silva Lepe
0

Puede crear un retraso "falso" entre animaciones infinitas simplemente con CSS. La forma de hacerlo es definir inteligentemente los puntos de animación de los fotogramas clave y la velocidad de duración de la animación.

Por ejemplo, si quisiéramos animar una pelota que rebota y quisiéramos una buena demora de .5 a 1 s entre cada rebote, podemos hacer algo como:

@keyframes bounce{
    0%{
        transform: translateY(0);
    }
    50%{
        transform: translateY(25%);
    }
    75%{
        transform: translateY(15%);
    }
    90%{
        transform: translateY(0%);
    }
    100%{
        transform: translateY(0);
    }
}

Lo que hacemos es asegurarnos de que la bola vuelva a su posición original mucho antes del 100%. En mi ejemplo, lo estoy haciendo en un 90%, lo que me proporcionó una demora de alrededor de .1, lo que fue lo suficientemente bueno para mí. Pero, obviamente, para su caso, puede agregar más puntos de fotogramas clave y cambiar los valores de transformación.

Además, puede agregar una duración de animación adicional para equilibrar sus animaciones de fotogramas clave.

Por ejemplo:

 animation: bounce .5s ease-in-out infinite;

Digamos que queríamos que la animación completa terminara en .5s, pero queríamos .2s adicionales de retraso entre las animaciones.

 animation: bounce .7s ease-in-out infinite;

Así que agregaremos un retraso adicional de .2s, y en nuestras animaciones de fotogramas clave, podemos agregar más puntos porcentuales para llenar los huecos del retraso de .2s.

alex067
fuente
Normalmente termino haciendo esto. la desventaja es que se vuelve realmente difícil modificar la animación, porque cada cambio en el tiempo requiere que se cambien todos los valores. a menos que lo configure correctamente con muchas variables atrevidas, lo que suele ser demasiado esfuerzo.
Beppe
0

para un flash de borde: en realidad muy simple: reemplace del a al 99% de negro y, por ejemplo, al 1% del cambio a azul, incluso puede acortarlo, el tiempo de animación se establece en, por ejemplo, 5 segundos.

@keyframes myborder {
  0% {border-color: black;}
  99% {border-color:black;}
  100% {border-color: blue;}
 }
Alex
fuente