99 votes

Délai de répétition de l'animation CSS

J'ai récemment découvert comment utiliser "correctement" les animations CSS (auparavant, je les rejetais car elles ne permettaient pas de réaliser des séquences complexes comme en JavaScript). Je suis donc en train d'apprendre à les connaître.

Pour cet effet, j'essaie de faire en sorte qu'un gradient "flare" balaye un élément de type barre de progression. Cet effet est similaire à celui des barres de progression natives 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;
}

Comme vous pouvez le voir, j'essaie d'avoir un délai de 4 secondes, suivi par le balayage de la brillance en 1 seconde, répété.

Cependant, il semble que le animation-delay ne s'applique qu'à la première itération, après quoi l'éclat continue à se propager de manière répétée.

J'ai "résolu" ce problème comme suit :

@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;
}

from y 80% sont exactement les mêmes, ce qui entraîne un "retard" de 80% de la durée de l'animation.

Cela fonctionne, mais pour ma prochaine animation, j'ai besoin que le délai soit variable (constant pour un élément particulier, mais variable parmi les éléments qui utilisent l'animation), alors que l'animation elle-même reste exactement de la même longueur.

Avec la "solution" ci-dessus, je me retrouverais avec une animation plus lente alors que tout ce que je veux, c'est un délai plus long.

Est-il possible d'avoir le animation-delay s'applique à toutes les itérations, et pas seulement à la première ?

67voto

Sebastian Thomas Points 119

J'ai eu un problème similaire et j'ai utilisé

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

Il est un peu irritant de devoir falsifier sa durée pour tenir compte des "retards" à chaque extrémité.

22voto

tim Points 645

Minitech a raison sur ce point animation-delay spécifie le délai avant le début de l'animation et PAS le délai entre les itérations. Le projet de la rédaction de la spécification le décrit bien et il y a eu une discussion sur cette fonctionnalité que vous décrivez. aquí qui suggère cette caractéristique de retard d'itération.

Bien qu'il existe peut-être une solution de contournement en JS, vous pouvez simuler ce délai d'itération pour la barre de progression en utilisant uniquement les CSS.

En déclarant le div de la fusée position:absolute et le div parent overflow: hidden en fixant l'état de l'image clé de 100 % à une valeur supérieure à la largeur de la barre de progression, et jouer avec la fonction de synchronisation cubique-bezier et les valeurs de décalage à gauche, vous êtes en mesure d'émuler une ease-in-out o linear avec un "retard".

Il serait intéressant d'écrire un mixin less/scss pour calculer exactement le décalage à gauche et la fonction de synchronisation pour obtenir ce résultat exact, mais je n'ai pas le temps de m'en occuper pour le moment. Mais j'aimerais bien voir quelque chose comme ça !

Voici une démo que j'ai réalisée pour montrer cela. (J'ai essayé d'émuler la barre de progression de Windows 7 et je n'y suis pas arrivé, mais cela démontre ce dont je parle).

Démonstration : 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;
}

16voto

Eric Johnson Points 539

Une autre façon d'obtenir une pause entre les animations est d'appliquer une deuxième animation qui cache l'élément pendant le délai que vous souhaitez. Cela présente l'avantage de vous permettre d'utiliser une fonction d'assouplissement CSS comme vous le feriez normalement.

.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;
  }
}

Cela ne fonctionne que si vous souhaitez que le délai soit un multiple de la durée de l'animation. Je l'ai utilisé pour rendre une pluie d'étoiles filantes plus aléatoire : https://codepen.io/ericdjohnson/pen/GRpOgVO

12voto

TalkativeTree Points 356

C'est ce que vous devriez faire. Vous devriez avoir une animation d'une seconde, puis un délai de 4 secondes entre les itérations :

@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;
}

J'ai donc beaucoup travaillé sur ce sujet et il est possible de le faire sans trop de difficultés. C'est la façon la plus simple de mettre un délai entre les itérations de l'animation qui est 1. SUPER FACILE et 2. nécessite juste un peu de logique. Regardez cette animation de danse que j'ai faite :

.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);
  }
}

En fait, je suis venu ici en essayant de trouver comment mettre un délai dans l'animation, quand j'ai réalisé qu'il suffisait 1. d'allonger la durée de l'animation et de mettre une chemise dans la proportion de temps pour chaque animation. Avant, elles duraient chacune 0,5 seconde, pour une durée totale de 2,5 secondes. Maintenant, disons que je veux ajouter un délai égal à la durée totale, donc un délai de 2,5 secondes.

Votre temps d'animation est de 2,5 secondes et le délai est de 2,5, vous changez donc la durée en 5 secondes. Cependant, comme vous avez doublé la durée totale, vous voudrez diviser par deux la proportion des animations. Regardez la finale ci-dessous. Cela a parfaitement fonctionné pour moi.

@-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 résumé :

Ce sont les calculs que vous utiliserez probablement pour déterminer comment modifier la durée de votre animation et le pourcentage de chaque partie.

durée_désirée = x

durée_désirée = durée_partie_de_l'animation1 + durée_partie_de_l'animation2 + ... (et ainsi de suite)

délai souhaité = y

durée totale = x + y

animation_part_duration1_actuel = animation_part_duration1 * durée souhaitée / durée totale

6voto

cuth Points 504

Je préfère écrire un peu de JavaScript plutôt que de rendre le CSS moins facile à gérer.

Tout d'abord, n'appliquez l'animation CSS que lors d'un changement d'attribut de données :

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

Ajoutez ensuite du javascript pour faire basculer l'animation à la moitié du délai.

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

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

Ou si vous ne voulez pas que l'animation s'exécute lorsque l'onglet est masqué :

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();

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X