Reputation: 2254
The .animate()
function in jQuery does not allow all CSS3 animatable properties to be animated (for example, background-color
). Is there a nice, standard way to dynamically create, apply, and remove CSS3 animations to elements on the page?
I'm currently following the example here but this is clunky and feels wrong. While it works, I would rather a better solution (using a library or something like that).
Upvotes: 3
Views: 1285
Reputation: 89750
Yes, we can dynamically create, apply and remove CSS3 animations to an element in the page.
To dynamically create an animation, we need to use the insertRule
or addRule
functions to add the @keyframes
rules and append it to the stylesheet. Once the animation is appended, applying it to the element is very simple, we just need to set the required property value to the animation
property via inline styles. Removing it agian is very simple, we just need to set the value back to null when it needs to be removed.
In the below snippet, I have first inserted an animation and applied it to the element on load. When the animation starts, the element fires the animationstart
event. Within this event listener, I've obtained the outerHTML
of the element that is being animated and printed it to show how inline style is present and then at the end of the animation (using the animationend
event listener), I've removed the inline style and printed the outerHTML
after it to show how it no longer has the animation.
There are no other simpler ways to dynamically create CSS3 animations. All possible solutions will involve creating and appending @keyframes
to the stylesheets using basic insertRule
, addRule
or the keyframes specific appendRule
function (which is used to append rules to an existing keyframe).
var elm = document.querySelector('.to-animate');
var op = document.querySelector('.output');
var animName = "shake-up-down",
animDuration = "3s",
animTiming = "linear",
animFillMode = "forwards",
animIteration = "3";
var ruleText = "0% {transform: translateY(0px);}";
ruleText += "25% {transform: translateY(10px);}";
ruleText += "75% {transform: translateY(-10px);}";
ruleText += "100% {transform: translateY(0px);}";
/* From David Walsh's blog */
function addCSSAnimRule(sheet, name, rules, index) {
if ("insertRule" in sheet) {
sheet.insertRule("@keyframes " + name + "{" + rules + "}", index);
} else if ("addRule" in sheet) {
sheet.addRule("@keyframes " + name, rules, index);
}
}
/* Self written */
function applyAnimation(elm, name, duration, timing, iteration, fillmode) {
elm.style["animation"] = name + " " + duration + " " + timing + " " + iteration + " " + fillmode;
/* or if you want to set them individually, comment the above line and uncomment this
elm.style["animationName"] = name;
elm.style["animationDuration"] = duration;
elm.style["animationTimingFunction"] = timing;
elm.style["animationIterationCount"] = iteration
elm.style["animationFillMode"] = fillmode;*/
}
addCSSAnimRule(document.styleSheets[0], animName, ruleText, 0);
applyAnimation(elm, animName, animDuration, animTiming, animIteration, animFillMode);
/* to print output */
elm.addEventListener("animationstart", function(e) {
op.textContent = "Animation " + e.animationName + " has started.";
op.textContent += "\n\nElement's Outer HTML: \n";
op.textContent += elm.outerHTML;
op.textContent += "\n\n------------------------------------------------------------------------------";
});
elm.addEventListener("animationend", function(e) {
elm.removeAttribute("style"); /* remove the animation */
op.textContent += "\nAnimation " + e.animationName + " has ended.";
op.textContent += "\n\nElement's Outer HTML: \n";
op.textContent += elm.outerHTML;
op.textContent += "\n\n------------------------------------------------------------------------------";
});
.to-animate {
height: 100px;
width: 100px;
margin: 10px;
border: 1px solid red;
}
<div class='to-animate'></div>
<pre class='output'></pre>
This method can be used to dynamically create and use any type of animation. Below snippet creates and adds a background-color
animation.
var elm = document.querySelector('.to-animate');
var op = document.querySelector('.output');
var animName = "bgColor",
animDuration = "4s",
animTiming = "linear",
animFillMode = "forwards",
animIteration = "3";
var ruleText = "0% {background-color: red;}";
ruleText += "25% {background-color: orange;}";
ruleText += "50% {background-color: yellow;}";
ruleText += "75% {background-color: pink;}";
ruleText += "100% {background-color: red;}";
/* From David Walsh's blog */
function addCSSAnimRule(sheet, name, rules, index) {
if ("insertRule" in sheet) {
sheet.insertRule("@keyframes " + name + "{" + rules + "}", index);
} else if ("addRule" in sheet) {
sheet.addRule("@keyframes " + name, rules, index);
}
}
/* Self written */
function applyAnimation(elm, name, duration, timing, iteration, fillmode) {
elm.style["animation"] = name + " " + duration + " " + timing + " " + iteration + " " + fillmode;
/* or if you want to set them individually, comment the above line and uncomment this
elm.style["animationName"] = name;
elm.style["animationDuration"] = duration;
elm.style["animationTimingFunction"] = timing;
elm.style["animationIterationCount"] = iteration
elm.style["animationFillMode"] = fillmode;*/
}
addCSSAnimRule(document.styleSheets[0], animName, ruleText, 0);
applyAnimation(elm, animName, animDuration, animTiming, animIteration, animFillMode);
/* to print output */
elm.addEventListener("animationstart", function(e) {
op.textContent = "Animation " + e.animationName + " has started.";
op.textContent += "\n\nElement's Outer HTML: \n";
op.textContent += elm.outerHTML;
op.textContent += "\n\n------------------------------------------------------------------------------";
});
elm.addEventListener("animationend", function(e) {
elm.removeAttribute("style"); /* remove the animation */
op.textContent += "\nAnimation " + e.animationName + " has ended.";
op.textContent += "\n\nElement's Outer HTML: \n";
op.textContent += elm.outerHTML;
op.textContent += "\n\n------------------------------------------------------------------------------";
});
.to-animate {
height: 100px;
width: 100px;
margin: 10px;
background-color: red;
}
<div class='to-animate'></div>
<pre class='output'></pre>
Cross Browser Version:
Here is a cross browser version with support for older browsers using methods exposed by the Prefix free library. This was tested in IE10+, Edge, Chrome v50 (dev-m), Firefox v43, Opera v35. Testing for prefixed version was done in Safari 5.1.7 on Win 10.
Upvotes: 2