jQuery 如何动态创建“@-Keyframe”CSS 动画?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18481550/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to dynamically create '@-Keyframe' CSS animations?
提问by Jagadeesh J
I have a requirement to rotate a div and stop at a particular position ( The value will be received from the server).
我需要旋转 div 并停在特定位置(将从服务器接收该值)。
I tried native JS to rotate and stop but it is eating up my CPU big time.
我尝试使用原生 JS 进行旋转和停止,但它占用了我大量的 CPU。
I can rotate with CSS animation but I need to create a class which will dynamically describe where to stop the animation. Something like
我可以使用 CSS 动画进行旋转,但我需要创建一个类来动态描述停止动画的位置。就像是
@-webkit-keyframes spinIt {
100% {
-webkit-transform: rotate(A_DYNAMIC_VALUE);
}
}
@-moz-keyframes spinIt {
100% {
-webkit-transform: rotate(A_DYNAMIC_VALUE);
}
}
Here is one reference
这是一个参考
Thanks in Advance
提前致谢
采纳答案by Deep Sharma
well i don't think it is easy to create dynamic @keyframes
they are inflexible because they must be hard-coded.
好吧,我认为创建动态并不容易,@keyframes
它们不灵活,因为它们必须是硬编码的。
Transitions are a little easier to work with, as they can gracefully respond to any CSS changes performed by JavaScript.
过渡更容易使用,因为它们可以优雅地响应 JavaScript 执行的任何 CSS 更改。
However, the complexity that CSS transitions can give you is pretty limited — an animation with multiple steps is difficult to achieve.
然而,CSS 过渡可以给你带来的复杂性非常有限——一个包含多个步骤的动画很难实现。
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.
这是 CSS @keyframe 动画旨在解决的问题,但它们不提供过渡所做的动态响应级别。
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.
Link1:一个工具,可以生成带有许多小步骤的 @-webkit-keyframe 动画。这为无限选择的缓动公式打开了大门。
Link2it 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.
Link2将它作为基础对您有很大帮助,因为它提供了一个 UI 来创建动画并将其导出到 CSS 代码。
I guessthissolution will definitely work for you. Its is used for dynamic keyframes
我想这个解决方案肯定对你有用。它用于动态关键帧
回答by Alex Grande
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);
回答by Deep Sharma
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 inertRule. 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.
亚历克斯格兰德的回答对几个关键帧非常有效。但是,假设您想一遍又一遍地动态添加关键帧,那么您的网页会很快变得非常滞后。要解决这个问题,只需停止创建新的 DOM 元素。相反,创建 1 个新的 DOM 样式表,然后使用 inertRule 重用它。如果你想要更多的关键帧(比如你在每个动画帧中生成一个新的关键帧),那么你需要设置一个系统,在它们不再使用后删除旧的关键帧。这是如何实现这样的事情的良好开端。
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...
此外,亚历克斯大,我敢肯定,document.getElementsByTagName('head')[0]
并且type = 'text/css'
还没有被IE8需要,并且@keyframes
不支持,直到IE10。就是说...
回答by sandrina-p
Let me share an updated (2019) answer to this.
让我分享一个更新的(2019 年)答案。
Yes, it's possible without Javascriptusing CSS Variables(supported by all modern browsers).
是的,不用 Javascript 也可以使用CSS 变量(所有现代浏览器都支持)。
--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
请参阅有关带有 CSS 变量的Codepen动态 CSS 动画的演示
Edit: Here's a CSS Tricks article about it too.
编辑:这是一篇关于它的CSS Tricks 文章。
回答by WheatBerry
You can change the style in CSSKeyframeRule, and this works fine for me in Chrome, just as the code below. Hope this will help:)
您可以更改 CSSKeyframeRule 中的样式,这对我来说在 Chrome 中很好用,就像下面的代码一样。希望这会有所帮助:)
<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>
回答by Martin Wantke
In JavaScript is it possible to access to the style sheet with document.styleSheets. Every sheet has a ruleand/or cssRulelist (browser depending) and a CSSStyleSheet.insertRule()method.
在 JavaScript 中,可以使用document.styleSheets访问样式表。每个工作表都有一个规则和/或cssRule列表(取决于浏览器)和一个CSSStyleSheet.insertRule()方法。
This method allows you to add a new keyframe raw as a string:
此方法允许您将新的关键帧原始添加为字符串:
JavaScript
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
html
<div id="box"></div>
回答by Matthias Southwick
You could create a new stylesheet with the animation you want in it. For Example:
您可以使用所需的动画创建一个新样式表。例如:
function addAnimation(keyframe){
var ss=document.createElement('style');
ss.innerText=keyframe;
document.head.appendChild(ss);
}
This would create a new stylesheet with your animation.
This method has only been tested in Chrome.
这将为您的动画创建一个新的样式表。
此方法仅在 Chrome 中进行过测试。
回答by Danziger
You can create a <style>
element, set its content to the CSS you want, in this case, the declaration of your animation and add it to the <head>
of the page.
您可以创建一个<style>
元素,将其内容设置为您想要的 CSS,在本例中为您的动画声明,并将其添加到<head>
页面的 。
Also, as others have suggested, if you need to create many different animations, then it would be better to reuse a single <style>
tag rather than creating multiple of them and add the new styles using CSSStyleSheet.insertRule()
.
此外,正如其他人所建议的,如果您需要创建许多不同的动画,那么最好重用单个<style>
标签而不是创建多个标签并使用CSSStyleSheet.insertRule()
.
Lastly, if you can use ES6's template literals/strings, your code will look much cleaner:
最后,如果您可以使用 ES6 的模板字面量/字符串,您的代码将看起来更简洁:
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>
Or even better:
或者甚至更好:
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>
回答by cippu_lux
the user7892745 wont work for me, need some little adjustement
user7892745 对我不起作用,需要一些小调整
1° "pos" not understand wot should be, but the console log say "undefined" so I've remove " , pos"
1° "pos" 不明白 wot 应该是什么,但控制台日志说 "undefined" 所以我删除了 ", pos"
2° " myReuseableStylesheet.insertRule" give me error " is not a function" so I used "innerHTML" insted of "insertRule"
2°“myReuseableStylesheet.insertRule”给我错误“不是一个函数”所以我使用了“insertRule”的“innerHTML”
3° finally I've moved " document.head.appendChild( myReuseableStylesheet );" at the end
3° 最后我移动了“document.head.appendChild(myReuseableStylesheet);” 在末尾
but after this it work fine and it's exact what I looking for. thanks a lot user7892745 :D
但在此之后它工作正常,这正是我要找的。非常感谢 user7892745 :D
maybe the problem I had, come form the way I use it
也许是我遇到的问题,形成我使用它的方式
this is the script i used with it
这是我使用的脚本
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);
}
i know thath a html marquee cuold seem symple to do the same thing, but dont work well,
我知道 html marquee cuold 似乎很容易做同样的事情,但效果不佳,