Programmatically Changing Webkit-Transformation Values in Animation Rules

programmatically changing webkit-transformation values in animation rules

Use the CSSOM

var style = document.documentElement.appendChild(document.createElement("style")),
rule = " run {\
0% {\
-webkit-transform: translate3d(0, 0, 0); }\
transform: translate3d(0, 0, 0); }\
}\
100% {\
-webkit-transform: translate3d(0, " + your_value_here + "px, 0);\
transform: translate3d(0, " + your_value_here + "px, 0);\
}\
}";
if (CSSRule.KEYFRAMES_RULE) { // W3C
style.sheet.insertRule("@keyframes" + rule, 0);
} else if (CSSRule.WEBKIT_KEYFRAMES_RULE) { // WebKit
style.sheet.insertRule("@-webkit-keyframes" + rule, 0);
}

If you want to modify a keyframe rule in a stylesheet that's already included, do the following:

var
stylesheet = document.styleSheets[0] // replace 0 with the number of the stylesheet that you want to modify
, rules = stylesheet.rules
, i = rules.length
, keyframes
, keyframe
;

while (i--) {
keyframes = rules.item(i);
if (
(
keyframes.type === keyframes.KEYFRAMES_RULE
|| keyframes.type === keyframes.WEBKIT_KEYFRAMES_RULE
)
&& keyframes.name === "run"
) {
rules = keyframes.cssRules;
i = rules.length;
while (i--) {
keyframe = rules.item(i);
if (
(
keyframe.type === keyframe.KEYFRAME_RULE
|| keyframe.type === keyframe.WEBKIT_KEYFRAME_RULE
)
&& keyframe.keyText === "100%"
) {
keyframe.style.webkitTransform =
keyframe.style.transform =
"translate3d(0, " + your_value_here + "px, 0)";
break;
}
}
break;
}
}

If you don't know the order but do know the URL of the CSS file, replace document.styleSheets[0] with document.querySelector("link[href='your-css-url.css']").sheet.

Javascript to change keyframe values in external css sheet (No Inline Style Changes!)

It is possible to change keyframes on loaded stylesheets. Here you have a stack overflow answer from 2011. And here's a link to a recent blog post about it.

Can I pass a value to a CSS function?

My answer: No you can not.

But you can create the whole CSS using PHP. The best bet is to use PHP to generate the entire CSS esp the one you need to modify according to the user settting.

Set the webkit-keyframes from/to parameter with JavaScript

A solution of sorts:

var cssAnimation = document.createElement('style');
cssAnimation.type = 'text/css';
var rules = document.createTextNode('@-webkit-keyframes slider {'+
'from { left:100px; }'+
'80% { left:150px; }'+
'90% { left:160px; }'+
'to { left:150px; }'+
'}');
cssAnimation.appendChild(rules);
document.getElementsByTagName("head")[0].appendChild(cssAnimation);

Just adds a style definition to the header. Would be much cleaner/better to define it though the DOM if possible.

Edit: Error in Chrome with old method

Cannot dynamically set initial element translation before transition in same call stack

Because of the computation costs associated with each reflow, most browsers optimize the reflow process by queuing changes and performing them in batches. In this case, you are overwriting the inline style information of the elements, which the browser recognizes. The browser queues the first change and then the second before finally deciding that a reflow should occur, which it does all-at-once. (It doesn't matter that you have separated the changes into two function calls.) This would similarly happen when trying to update any other style property.

You can always force the browser to reflow by using any of the following:

  • offsetTop, offsetLeft, offsetWidth, offsetHeight
  • scrollTop, scrollLeft, scrollWidth, scrollHeight
  • clientTop, clientLeft, clientWidth, clientHeight
  • getComputedStyle() (currentStyle in IE)

So just change your first function to this:

var computedStyles = [];

function setAnimation() {
div1.style.webkitTransform = 'matrix(1,0,0,1,1200,0)';
div2.style.webkitTransform = 'matrix(1,0,0,1,0,0)';

// force div's 1 and 2 to reflow
computedStyles[div1] = div1.clientHeight;
computedStyles[div2] = div2.clientHeight;
}

And now the browser will perform the initial transformations. You don't need two functions to accomplish this, just force the reflow in-between.

Due to some headaches that can occur when trying to solve reflow/repaint issues like this, I always suggest using CSS animations, even if you have to dynamically create and remove style rules from a stylesheet using the CSSOM. Read more here: programmatically changing webkit-transformation values in animation rules

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 the keyframes value of css with jQuery

You could use a CSS variable and change that:

setTimeout(() => {

console.log("changing");

document.getElementById("fizz").style.setProperty("--foo", "green");

}, 2000);
:root {

--foo: blue;

}

@keyframes hello {

from {

background-color: yellow;

}

to {

background-color: var(--foo);

}

}

#fizz {

height: 1em;

animation: 1s infinite alternate hello;

}
<div id="fizz">

<div>

Clean way to programmatically use CSS transitions from JS?

There isn't a clean way at this moment (without using CSS Animations -- see the nearby answer by James Dinsdale for an example using CSS Animations). There is a spec bug 14617, which unfortunately wasn't acted upon since it was filed in 2011.

setTimeout does not work reliably in Firefox (this is by design).

I'm not sure about requestAnimationFrame -- an edit to the original question says it doesn't work reliably either, but I did not investigate. (Update: it looks like requestAnimationFrame is considered at least by one Firefox core developer to be the place where you can make more changes, not necessarily see the effect of the previous changes.)

Forcing reflow (e.g. by accessing offsetHeight) is a possible solution, but for transitions to work it should be enough to force restyle (i.e. getComputedStyle): https://timtaubert.de/blog/2012/09/css-transitions-for-dynamically-created-dom-elements/

window.getComputedStyle(elem).opacity;

Note that just running getComputedStyle(elem) is not enough, since it's computed lazily. I believe it doesn't matter which property you ask from the getComputedStyle, the restyle will still happen. Note that asking for geometry-related properties might cause a more expensive reflow.

More information on reflow/restyle/repaint: http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/



Related Topics



Leave a reply



Submit