web-dev-qa-db-fra.com

Comment créer dynamiquement des animations CSS '@ -Keyframe'?

J'ai l'obligation de faire pivoter une div et de m'arrêter à une position particulière (la valeur sera reçue du serveur).

JS a essayé de tourner et d’arrêter JS en mode natif, mais c’est trop gros pour mon processeur.

Je peux effectuer une rotation avec une animation CSS mais je dois créer une classe qui décrira dynamiquement où arrêter l'animation. Quelque chose comme 

@-webkit-keyframes spinIt {
    100% {
        -webkit-transform: rotate(A_DYNAMIC_VALUE);
    }
}
@-moz-keyframes spinIt {
    100% {
        -webkit-transform: rotate(A_DYNAMIC_VALUE);
    }
}

Voici une référence 

http://jsfiddle.net/bVkwH/8/

Merci d'avance

46
Jagadeesh J

eh bien, je ne pense pas qu'il soit facile de créer dynamique @keyframes ils sont inflexibles car ils doivent être codés en dur.

Les transitions sont un peu plus faciles à utiliser, car elles peuvent répondre gracieusement à toutes les modifications CSS effectuées par JavaScript.

Cependant, la complexité que les transitions CSS peuvent vous donner est assez limitée - une animation en plusieurs étapes est difficile à obtenir.

C’est un problème que les animations CSS @keyframe sont censés résoudre , mais elles n’offrent pas le niveau de réactivité dynamique des transitions.

mais ces liens pourraient vous aider

Link1 : un outil qui génère une animation @ -webkit-keyframe avec de nombreuses petites étapes. Cela ouvre la porte à une sélection illimitée de formules d’atténuation.

Link2 il vous sera d'une grande aide de le prendre comme base car il fournit une interface utilisateur pour créer des animations et des exportations. en code CSS.

Je suppose que this solution fonctionnera certainement pour vous. Son est utilisé pour les images clés dynamiques

32
Deep Sharma

Vous pouvez insérer des règles de feuille de style de manière dynamique pour remplacer les styles précédents dans l'en-tête. Cela évite d’ajouter une autre bibliothèque pour une tâche unique.

var style = document.createElement('style');
style.type = 'text/css';
var keyFrames = '\
@-webkit-keyframes spinIt {\
    100% {\
        -webkit-transform: rotate(A_DYNAMIC_VALUE);\
    }\
}\
@-moz-keyframes spinIt {\
    100% {\
        -webkit-transform: rotate(A_DYNAMIC_VALUE);\
    }\
}';
style.innerHTML = keyFrames.replace(/A_DYNAMIC_VALUE/g, "180deg");
document.getElementsByTagName('head')[0].appendChild(style);
44
Alex Grande

La réponse d'Alex Grande fonctionne très bien pour quelques images clés. Mais disons que vous souhaitez continuer à ajouter des images-clés de manière dynamique, votre page Web devient très lente, très rapide. Pour résoudre ce problème, arrêtez simplement de créer de nouveaux éléments DOM. Créez plutôt une nouvelle feuille de style DOM et réutilisez-la simplement avec inertRule. Si vous voulez encore plus d'images clés (par exemple, si vous générez une nouvelle image clé à chaque image d'animation), vous devez configurer un système qui supprime les anciennes images clés lorsqu'elles ne sont plus utilisées. C’est un bon début pour réaliser ce genre de chose.

var myReuseableStylesheet = document.createElement('style'),
    addKeyFrames = null;
document.head.appendChild( myReuseableStylesheet );
if (CSS && CSS.supports && CSS.supports('animation: name')){
    // we can safely assume that the browser supports unprefixed version.
    addKeyFrames = function(name, frames){
        var pos = myReuseableStylesheet.length;
        myReuseableStylesheet.insertRule(
            "@keyframes " + name + "{" + frames + "}", pos);
    }
} else {
    addKeyFrames = function(name, frames){
        // Ugly and terrible, but users with this terrible of a browser
        // *cough* IE *cough* don't deserve a fast site
        var str = name + "{" + frames + "}",
            pos = myReuseableStylesheet.length;
        myReuseableStylesheet.insertRule("@-webkit-keyframes " + str, pos);
        myReuseableStylesheet.insertRule("@keyframes " + str, pos+1);
    }
}

Exemple d'utilisation:

addKeyFrames(
    'fadeAnimation',
    '0%{opacity:0}' + 
    '100%{opacity:1}'
);

En outre, Alex Grande, je suis à peu près sûr que document.getElementsByTagName('head')[0] et type = 'text/css' n'ont pas été nécessaires depuis IE8, et @keyframes ne sont pas pris en charge avant IE10. Juste en disant ...

6
user7892745

Vous pouvez changer le style dans CSSKeyframeRule et cela fonctionne très bien pour moi dans Chrome, tout comme le code ci-dessous . J'espère que cela vous aidera :)

<html>

<head>
	<style>
		#text {
			display: inline-block;
		}
	</style>
</head>

<body>
	<div id="text">TEXT</div>
	<script>
	
		// Dynamically create a keyframe animation
		document.styleSheets[0].insertRule('\
			@keyframes anim {\
				from { transform: rotateZ(0deg);   }\
				to   { transform: rotateZ(360deg); }\
			}'
		);
		var div = document.getElementById('text');
		div.style.animation = 'anim 1s linear forwards';
		
		// This function will change the anim
		function stopAtSomeDeg(d) {
			var ss = document.styleSheets[0];
			var anim;
			for (var i in ss.cssRules) {
				// Find your animation by name
				if (ss.cssRules[i].name === 'anim') {
					anim = ss.cssRules[i];
					break;
				}
			}
			var stopFrame = anim.cssRules[1]; // This indicates the second line of "anim" above.
			
			// Change any attributes
			stopFrame.style.transform = 'rotateZ(' + d + 'deg)';
		}
		
		stopAtSomeDeg(180);
	</script>
</body>
</html>

1
WheatBerry

En JavaScript, il est possible d'accéder à la feuille de style avec document.styleSheets. Chaque feuille a une liste règle et/ou cssRule (selon le navigateur) et une méthode CSSStyleSheet.insertRule () .

Cette méthode vous permet d’ajouter une nouvelle image clé brute sous forme de chaîne:

JavaScript

function insertStyleSheetRule(ruleText)
{
    let sheets = document.styleSheets;

    if(sheets.length == 0)
    {
        let style = document.createElement('style');
        style.appendChild(document.createTextNode(""));
        document.head.appendChild(style);
    }

    let sheet = sheets[sheets.length - 1];
    sheet.insertRule(ruleText, sheet.rules ? sheet.rules.length : sheet.cssRules.length);
}

document.addEventListener("DOMContentLoaded", event =>
{
    insertStyleSheetRule("@keyframes spinIt { 0% { transform: rotate(-20deg); } 100% { transform: rotate(20deg); } }");

    insertStyleSheetRule("#box { " + 
        "animation: spinIt 1s infinite alternate cubic-bezier(0.5,0,0.5,1); " + 
        "width: 64px; height: 64px; background-color: red; border: 4px solid black; " + 
    "}");
});

html

<div id="box"></div>

démo: https://jsfiddle.net/axd7nteu/

1
Martin Wantke

Vous pouvez créer un élément <style>, définir son contenu sur le CSS souhaité, dans ce cas, la déclaration de votre animation et l'ajouter au <head> de la page.

De plus, comme d'autres l'ont suggéré, si vous devez créer plusieurs animations différentes, il serait préférable de réutiliser une seule balise <style> plutôt que d'en créer plusieurs et d'ajouter les nouveaux styles à l'aide de CSSStyleSheet.insertRule() .

Enfin, si vous pouvez utiliser le template literals/strings de ES6, votre code paraîtra beaucoup plus propre:

let dynamicStyles = null;

function addAnimation(body) {
  if (!dynamicStyles) {
    dynamicStyles = document.createElement('style');
    dynamicStyles.type = 'text/css';
    document.head.appendChild(dynamicStyles);
  }
  
  dynamicStyles.sheet.insertRule(body, dynamicStyles.length);
}

addAnimation(`
  @keyframes myAnimation { 
    0% { transform: rotate(0); }
    20% { transform: rotate(${ 360 * Math.random() }deg); }
    60% { transform: rotate(${ -360 * Math.random() }deg); }
    90% { transform: rotate(${ 360 * Math.random() }deg); }
    100% { transform: rotate(${ 0 }deg); }
  }
`);

document.getElementById("circle").style.animation = 'myAnimation 3s infinite';
html,
body {
  height: 100vh;
}

body {
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0;
}

#circle {
  width: 100px;
  height: 100px;
  box-shadow:
    0 0 48px -4px rgba(0, 0, 0, .25),
    0 0 0 4px rgba(0, 0, 0, .02);
  border-radius: 100%;
  position: relative;
  overflow: hidden;
}

#circle::before {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  transform: translate(-2px);
  border-left: 4px solid #FFF;
  height: 24px;
  box-shadow: 0 -4px 12px rgba(0, 0, 0, .25);
}
<div id="circle"></div>

Ou même mieux:

let dynamicStyles = null;

function addAnimation(name, body) {
  if (!dynamicStyles) {
    dynamicStyles = document.createElement('style');
    dynamicStyles.type = 'text/css';
    document.head.appendChild(dynamicStyles);
  }
  
  dynamicStyles.sheet.insertRule(`@keyframes ${ name } {
    ${ body }
  }`, dynamicStyles.length);
}

addAnimation('myAnimation', `
  0% { transform: rotate(0); }
  20% { transform: rotate(${ 360 * Math.random() }deg); }
  60% { transform: rotate(${ -360 * Math.random() }deg); }
  90% { transform: rotate(${ 360 * Math.random() }deg); }
  100% { transform: rotate(${ 0 }deg); }
`);

document.getElementById("circle").style.animation = 'myAnimation 3s infinite';
html,
body {
  height: 100vh;
}

body {
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0;
}

#circle {
  width: 100px;
  height: 100px;
  box-shadow:
    0 0 48px -4px rgba(0, 0, 0, .25),
    0 0 0 4px rgba(0, 0, 0, .02);
  border-radius: 100%;
  position: relative;
  overflow: hidden;
}

#circle::before {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  transform: translate(-2px);
  border-left: 4px solid #FFF;
  height: 24px;
  box-shadow: 0 -4px 12px rgba(0, 0, 0, .25);
}
<div id="circle"></div>

0
Danziger

Vous pouvez créer une nouvelle feuille de style avec l'animation souhaitée . Par exemple:

function addAnimation(keyframe){
     var ss=document.createElement('style');
     ss.innerText=keyframe;
     document.head.appendChild(ss);
}

Cela créerait une nouvelle feuille de style avec votre animation .
Cette méthode n'a été testée que sous Chrome.

0
Matthias Southwick

Permettez-moi de partager une réponse mise à jour (2019) à ce sujet. ** Oui, c'est possible sans Javascript ** avec Variables CSS (supporté par tous les navigateurs modernes).

--lightScaleStart: 0.8;

.light {
    animation: grow 2s alternate infinite ease-in-out;
}

.light.yellow {
    --lightScaleEnd: 1.1;
}

.light.red {
    --lightScaleEnd: 1.2;
}

@keyframes grow {
  from {
    transform: scale(var(--lightScaleStart));
  }
  to {
    transform: scale(var(--lightScaleEnd));
  }
}

Voir la démo sur Codepen Animations CSS dynamiques avec des variables CSS

0
sandrina-p

le user7892745 ne fonctionnera pas pour moi, nécessite quelques ajustements

1 ° "pos" ne comprend pas ce que nous devrions savoir, mais le journal de la console indique "non défini" J'ai donc retiré ", pos"

2 ° "myReuseableStylesheet.insertRule" me donne une erreur "n'est pas une fonction" J'ai donc utilisé "innerHTML" au lieu de "insertRule"

3 ° enfin j'ai déplacé " Document.head.appendChild (myReuseableStylesheet);" à la fin

mais après cela fonctionne bien et c'est exactement ce que je cherche ... Merci beaucoup user7892745: D

peut-être que le problème que j'ai eu, vient de la façon dont je l'utilise

c'est le script que j'ai utilisé avec elle

var getclass = document.getElementsByClassName("cls");
var countclass = getclass.length;
for (var i=0; i <countclass; i++ ){
    getclass[i].addEventListener('mouseover', function(){
        // get the data-name value to show element whose id are the same
        var x=  this.getAttribute("data-name"); 
        var y =document.getElementById(x);
            y.style.display="block";
            // because the element to show have fixed width, but different text length, they have different height
            // so I need to get the highness, then use the value of height to define the 100% value of animation
            // or the longer ones will be cutted an the shorten have a lot of empty space a the end
        var yHeig= Math.round(parseInt(getComputedStyle(y).getPropertyValue('height')));
            yHeig_ = yHeig - 10; // to shorten a bit the time from end and new passage
        console.log(yHeig+" - "+ yHeig_);
        addKeyFrames(
                'showMe',
                '0%{top:35px;}' + 
                '100%{top:-'+ yHeig_ +'px;}'
            );
        y.style.animation="showMe 7s linear infinite";

    },false);

    getclass[i].addEventListener('mouseout', function(){
        var x=  this.getAttribute("data-name");
        document.getElementById(x).style.display="none";
    },false);
}

je sais que le html Marquee Cuold semble symple pour faire la même chose, mais ne fonctionne pas bien,

0
cippu_lux