How to dynamically create '@-Keyframe' CSS animations?

Solution 1:

You can insert stylesheet rules dynamically to override previous styles in the head. This helps avoid adding yet another library for a single task.

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

Solution 2:

well i don't think it is easy to create dynamic @keyframes they are inflexible because they must be hard-coded.

Transitions are a little easier to work with, as they can gracefully respond to any CSS changes performed by JavaScript.

However, the complexity that CSS transitions can give you is pretty limited — an animation with multiple steps is difficult to achieve.

This is a problem that CSS @keyframe animations are meant to solve, but they don’t offer the level of dynamic responsiveness that transitions do.

but these links might help you

Link1 : a tool that generates a @-webkit-keyframe animation with many tiny steps. This opens the door to an unlimited selection of easing formula.

Link2 it will be a great help for you to take it as a base as it provides a UI to create animations and exports it to CSS code.

I guess this solution will definitely work for you. Its is used for dynamic keyframes

Solution 3:

Let me share an updated (2019) answer to this.

Yes, it's possible without Javascript using CSS Variables (supported by all modern browsers).

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

See demo on Codepen Dynamic CSS Animations with CSS Variables

Edit: Here's a CSS Tricks article about it too.

Solution 4:

Alex Grande's answer works GREAT for a few keyframes. But, say you want to dynamically keep adding in keyframes over and over again, then your webpage get really laggy really quick. To solve this problem, just STOP creating new DOM elements. Rather, create 1 new DOM stylesheet, and just reuse it with the insertRule. If you want even more keyframes (like if you're generating a new keyframe every animationframe), then you need to set up a system which deletes old keyframes after they're no longer used. This is a good start to how something like this can be achieved.

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

Example usage:

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

Also, Alex Grande, I am pretty sure that document.getElementsByTagName('head')[0] and type = 'text/css' hasn't been needed since IE8, and @keyframes aren't supported till IE10. Just saying...

Solution 5:

You can change the style in CSSKeyframeRule, and this works fine for me in Chrome, just as the code below. Hope this will help:)

<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>