Set Webkit Keyframes Values Using JavaScript Variable

Set Webkit Keyframes Values Using Javascript Variable

Okay, not what your actual code looks like, but you can't throw JavaScript variables into CSS, it won't recognize them.

Instead, you need to create the CSS rules through JavaScript and insert them into the CSSOM (CSS Object Model). This can be done a few ways -- you can either just create a keyframe animation and add it in, or you can overwrite an existing animation. For this sake of this question, I'm going to assume you want to continually overwrite an existing keyframe animation with different rotation values.

I've put together (and documented) a JSFiddle for you to take a look at: http://jsfiddle.net/russelluresti/RHhBz/2/

It starts off running a -10 -> 10 degree rotation animation, but then you can click the button to have it execute a rotation between random values (between -360 and 360 degrees).

This example was hacked together primarily from earlier experimentation done by Simon Hausmann. You can see the source here: http://www.gitorious.org/~simon/qtwebkit/simons-clone/blobs/ceaa977f87947290fa2d063861f90c820417827f/LayoutTests/animations/change-keyframes.html (for as long as that link works, gitorious is pretty bad at maintaining urls).

I've also taken the randomFromTo JavaScript function code from here: http://www.admixweb.com/2010/08/24/javascript-tip-get-a-random-number-between-two-integers/

I've added documentation to the parts of the Simon Hausmann script that I've taken from him (though I've slightly modified them). I've also used jQuery just to attach the click event to my button--all other script is written in native JavaScript.

I've tested this for Chrome 18 and Safari 5.1, and it seems to work fine in both browsers.

Hope this helps.

Change keyframes values in Javascript

Does it have to be a keyframe animation? Typically you would use the CSS transition property for this kind of animation powered by JavaScript, like this:

var width = 50;

document.getElementById('button').addEventListener('click', () => {
width += 50;
document.getElementById('box').style.width = `${width}px`;
});
#box {
background: red;
height: 50px;
width: 50px;
transition: width .5s;
margin-bottom: 1em;
}
<div id="box"></div>

<button id="button">Change Width</button>

How do I change @keyframes using JS?

I guess we are in the territory of CSS+JS = CJSSS thats lot of Ss to handle tbh. JS deals with Document object model and CSS deals with CSS object model. Browser object model deals with both of these.

That's being said JS have no interaction with CSSOM. What we see on screen is BOM taking the two and painting it on screen. It is when its painted aka DOM is represented Js is able to access and manipulate objects.

With above in mind when we change style values with JS e.g. element.style.height=100% it is happening after the fact widely known as computed value.

By computed it refers to what got painted on screen so element.height would return hight in pixels not the CSS rule from which it was painted that being percentage.

Thus when we are intending to change @keyframe we are intending to manipulate CSS rule before the fact not after the fact. thats problem no 1.

BOM only provides set number of CSS style properties to be manipulated through style function e.g. height color etc It does not include @keyframe in that set.

so we have to do some leg work to handle it after the fact.

root = document.documentElement;


setTimeout(function(){ root.style.setProperty('--change', 30 + "px"); }, 5000);
:root {
--change: 280px;
}
#progressBar{
background-color: #247BA0;
width: 150px;
padding: 10px;
border-radius: 5px;
animation: progressBar 3s ease;
animation-fill-mode:both;
text-align: center;
box-sizing: content-box;
}


@keyframes progressBar {
0% { width: 0; }
100% { width: var(--change); }
}
<div id="progressBar"></div>

generate @-webkit-keyframes CSS dynamically with JavaScript?

Yes, i use Jquery library and then apply like so:

Say in this situation i want the left value to be dynamic from a div with attribute class value = "push"

<!--HTML-->
<div class="push">Wall</div>

//--JS--
var KeyFrame =
{
init: function(){
if(!KeyFrame.check)
{
//get the left position
var pushLeft = $('.push').position().left;
//set the style and append to head
var css = $('<style>@keyframes mymove{from {left:0px;}to {left:'+pushLeft+'px;}}</style>').appendTo('head'); //make sure you don't carriage return the css inline statement, or else it'll be error as ILLEGAL
//so u don't keep appending style to head
KeyFrame.check = true;
}
}
}
KeyFrame.init();

How to set a css animation class variable with Javascript/jQuery?

I don't think it's possible to concatenate a CSS variable with a string as you were trying in your CSS:

 transform: rotate(var(--rotation-degrees)+'deg');

It's better to handle that with JavaScript.

I think the main issue you're having is that the class needs to be removed after the animation has run (in order for it to be able to run again). You can do that with the animationend event listener.

Demo below:

const DIV = $('div');const BUTTON = $('#rotate-right-button');const SPAN = $('#variable-value');const PROPERTY_NAME = '--rotation-degrees';const DEG = 'deg';const ROOT = document.documentElement;const ElementClass = {  ROTATE_ANIMATION: 'animation-rotate'}const ROTATION_VALUE = 90;const Event = {  CLICK: 'click',  ANIMATION_END: 'animationend'}
let degrees = 0;
function rotate(degrees_increment) { degrees += degrees_increment; ROOT.style.setProperty(PROPERTY_NAME, degrees + DEG); SPAN.html(`${PROPERTY_NAME}: ${degrees + DEG}`);}
BUTTON.on(Event.CLICK, function() { DIV.addClass(ElementClass.ROTATE_ANIMATION); DIV.on(Event.ANIMATION_END, function(event) { $(this).removeClass(ElementClass.ROTATE_ANIMATION); }); rotate(ROTATION_VALUE);});
@keyframes rotate {  100% {    transform: rotate(var(--rotation-degrees));  }}
.animation-rotate { animation: rotate 0.2s;}
div { background: red; width: 100px; height: 100px;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><div></div><button id="rotate-right-button">rotate</button><br><span id="variable-value"></span>

Why do my CSS variables not affect keyframes animation?

In Blink and Webkit browsers, the values for the animation are parsed the first time the animation is set and not at every iteration, nor when the variables change.

You need to force a new animation for it to use the new variables:

  const rotaters = document.querySelectorAll('.rotater');
rotaters.forEach( (elem) => {
elem.style.animationName = "none";
});
//
// update the variables here
//
document.body.offsetWidth; // force a single reflow
rotaters.forEach( (elem, i) => {
elem.style.animationName = "rotation" + i;
});

let min = 0;
let max = 4;

let x;

let rotVar;
let rotVarStarts = [0, 0, 0, 0, 0, 0];
let rotVarEnds = [];


function getRandomInt() {
min = Math.ceil(min);
max = Math.floor(max);
x = Math.floor(Math.random() * (max - min) + min);
}

function resetStarts() {
for (let i = 0; i < 6; i++) {
rotVarStarts[i] = rotVarEnds[i];
}
}


function setEnds(){
for (let i = 0; i < 6; i++) {
getRandomInt();
if (x == 0) {
rotVar = 0; } else if
(x == 1) {
rotVar = 90; } else if
(x == 2) {
rotVar = 180; } else if
(x == 3) {
rotVar = 270; } else if
(x == 4) {
rotVar = 360; }
rotVarEnds[i] = rotVar;
}


const rotaters = document.querySelectorAll('.rotater');
rotaters.forEach( (elem) => {
elem.style.animationName = "none";
});

document.documentElement.style.setProperty('--rotate0a', rotVarStarts[0] + "deg");
document.documentElement.style.setProperty('--rotate0b', rotVarEnds[0] + "deg");

document.documentElement.style.setProperty('--rotate1a', rotVarStarts[1] +"deg");
document.documentElement.style.setProperty('--rotate1b', rotVarEnds[1] + "deg");

document.documentElement.style.setProperty('--rotate2a', rotVarStarts[2] + "deg");
document.documentElement.style.setProperty('--rotate2b', rotVarEnds[2] + "deg");

document.documentElement.style.setProperty('--rotate3a', rotVarStarts[3] + "deg");
document.documentElement.style.setProperty('--rotate3b', rotVarEnds[3] + "deg");

document.documentElement.style.setProperty('--rotate4a', rotVarStarts[4] + "deg");
document.documentElement.style.setProperty('--rotate4b', rotVarEnds[4] + "deg");

document.documentElement.style.setProperty('--rotate5a', rotVarStarts[5] + "deg");
document.documentElement.style.setProperty('--rotate5b', rotVarEnds[5] + "deg");

let test1 = getComputedStyle(document.documentElement).getPropertyValue('--rotate0a');
let test2 = getComputedStyle(document.documentElement).getPropertyValue('--rotate0b');
console.log(test1 + "//" + test2);

document.body.offsetWidth; // force a single reflow
rotaters.forEach( (elem, i) => {
elem.style.animationName = "rotation" + i;
});

}


setInterval(function () {
setEnds();
resetStarts();
}, 3000);
:root {
--rotate0a: 0deg;
--rotate0b: 90deg;
--rotate1a: 0deg;
--rotate1b: 0deg;
--rotate2a: 0deg;
--rotate2b: 0deg;
--rotate3a: 0deg;
--rotate3b: 0deg;
--rotate4a: 0deg;
--rotate4b: 0deg;
--rotate5a: 0deg;
--rotate5b: 0deg;
}

.wrapper {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}

.rotater {
width: 100%;
background-color: blue;
padding-bottom: 100%;
position: relative;
}

.zero {
animation: rotation0 1s infinite linear;
}

.one {
animation: rotation1 1s infinite linear;
}

.two {
animation: rotation2 1s infinite linear;
}

.three {
animation: rotation3 1s infinite linear;
}

.four {
animation: rotation4 1s infinite linear;
}

.five {
animation: rotation5 1s infinite linear;
}

.inner {
position: absolute;
top: 0;
left: 0;
}

@keyframes rotation0 {
from {
transform: rotate(var(--rotate0a));
}
to {
transform: rotate(var(--rotate0b));
}
}

@keyframes rotation1 {
from {
transform: rotate(var(--rotate1a));
}
to {
transform: rotate(var(--rotate1b));
}
}

@keyframes rotation2 {
from {
transform: rotate(var(--rotate2a));
}
to {
transform: rotate(var(--rotate2b));
}
}

@keyframes rotation3 {
from {
transform: rotate(var(--rotate3a));
}
to {
transform: rotate(var(--rotate3b));
}
}

@keyframes rotation4 {
from {
transform: rotate(var(--rotate4a));
}
to {
transform: rotate(var(--rotate4b));
}
}

@keyframes rotation5 {
from {
transform: rotate(var(--rotate5a));
}
to {
transform: rotate(var(--rotate5b));
}
}
<body onload = "setEnds()">
<div class = "wrapper">
<div class = "rotater zero">
<div class = "inner"></div>
</div>
<div class = "rotater one">
<div class = "inner"></div>
</div>
<div class = "rotater two">
<div class = "inner"></div>
</div>
<div class = "rotater three">
<div class = "inner"></div>
</div>
<div class = "rotater four">
<div class = "inner"></div>
</div>
<div class = "rotater five">
<div class = "inner"></div>
</div>
</div>
</body>

How to manipulate CSS @keyframes through JavaScript?

You can write the keyframe entirely with JavaScript as below, which gives you the ability to use dynamic values.

The Element interface's animate() method is a shortcut method which creates a new Animation, applies it to the element, then plays the animation. It returns the created Animation object instance. More and MDN's doc.