如何动态创建'@ -Keyframe'CSS动画?

时间:2013-08-28 07:16:38

标签: javascript jquery html css

我需要旋转div并停在特定位置(该值将从服务器接收)。

我尝试使用本机JS进行旋转和停止,但它耗费了我的CPU时间。

我可以使用CSS动画旋转,但我需要创建一个动态描述停止动画的位置的类。像

这样的东西
@-webkit-keyframes spinIt {
    100% {
        -webkit-transform: rotate(A_DYNAMIC_VALUE);
    }
}
@-moz-keyframes spinIt {
    100% {
        -webkit-transform: rotate(A_DYNAMIC_VALUE);
    }
}

这是一个参考

http://jsfiddle.net/bVkwH/8/

先谢谢

13 个答案:

答案 0 :(得分:46)

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

答案 1 :(得分:32)

我认为创建动态 @keyframes并不容易,因为它们必须是硬编码的。

转换更易于使用,因为它们可以优雅地响应JavaScript执行的任何CSS更改。

然而,CSS过渡所带来的复杂性非常有限 - 难以实现具有多个步骤的动画。

这是CSS @keyframe动画要解决的问题,但它们没有提供转换的动态响应级别。

但这些链接可能会对您有所帮助

Link1:一个生成带有许多微小步骤的@ -webkit关键帧动画的工具。这为无限选择的宽松配方打开了大门。

Link2 以它为基础将是一个很好的帮助,因为它提供了一个UI来创建动画并将其导出到CSS代码。

我想 this 解决方案绝对适合您。它用于动态关键帧

答案 2 :(得分:6)

亚历克斯格兰德的答案适用于几个关键帧。但是,假设你想要一遍又一遍地动态地继续添加关键帧,那么你的网页真的很快就会变得非常迟缓。要解决此问题,只需停止创建新的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);
    }
}

使用示例:

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

此外,Alex Grande,我非常确定自IE8以来不需要document.getElementsByTagName('head')[0]type = 'text/css',并且在IE10之前不支持@keyframes。只是说...

答案 3 :(得分:2)

您可以在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>

答案 4 :(得分:1)

在JavaScript中,可以使用 document.styleSheets 访问样式表。每个工作表都有规则和/或 cssRule 列表(取决于浏览器)和CSSStyleSheet.insertRule()方法。

此方法允许您添加新的关键帧raw 作为字符串

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

<div id="box"></div>

演示:https://jsfiddle.net/axd7nteu/

答案 5 :(得分:0)

user7892745不适合我,需要一些小调整

1°“pos”不明白应该是,但控制台日志说“未定义” 所以我删除了“,pos”

2°“myReuseableStylesheet.insertRule”给我错误“不是函数” 所以我使用了“insertRule”的“innerHTML”

3°终于我感动了“ document.head.appendChild(myReuseableStylesheet);“最后

但在此之后它工作正常,这正是我想要的。 非常感谢user7892745:D

也许我遇到的问题,就像我使用它的方式一样

这是我用它的脚本

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

我知道一个html选框cuold看起来很容易做同样的事情,但是效果不好,

答案 6 :(得分:0)

您可以创建一个<style>元素,将其内容设置为所需的CSS,在这种情况下,将其声明为动画,并将其添加到页面的<head>

而且,正如其他人所建议的那样,如果您需要创建许多不同的动画,那么最好重用单个<style>标签,而不是创建多个动画并使用{{3}添加新样式}。

最后,如果您可以使用ES6的CSSStyleSheet.insertRule(),您的代码将看起来更加简洁:

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>

甚至更好:

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>

答案 7 :(得分:0)

您可以使用所需的动画创建一个新的样式表。 例如:

function addAnimation(keyframe){
     var ss=document.createElement('style');
     ss.innerText=keyframe;
     document.head.appendChild(ss);
}

这将为您的动画创建一个新的样式表。
该方法仅在Chrome中经过测试。

答案 8 :(得分:0)

让我分享一个更新的(2019)答案。 **是的,如果没有Java脚本,则可以使用CSS Variables(受所有现代浏览器支持)。

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

请参阅有关Codepen Dynamic CSS Animations with CSS Variables的演示

答案 9 :(得分:0)

使用 CSS 变量:您可以使用元素的伪 :root 在 css 规则中声明一个 css 变量,然后使用 Javascript 操作该变量。

:root {--variable-name:property;} 基本上是文档的根元素 {{1} }.然后使用 JS 更改 CSS 根变量/s 的值:

<html>element.style.setProperty('--variable-name','value'。将声明的根变量 ) 作为名称传递并分配新值。然后在您的 --variable-name css 规则中,添加根变量名称,例如:@keyframesfrom: { top: var(--top-position),以偏移量 } 规则中的属性。示例:

@keyframe

那么 JS 会像这样:

:root {
  --top-position-start: 0px;
  --left-position-start: 0px;
  --top-position-end: 200px;
  --left-position-end: 200px;
}

.element {
  top: var(--top-position-start);
  left: var(--left-position-start);
  animation: movePos 1s ease-in;
}

@keyframes movePos {
  from: {
    top: var(--top-position-start);
    left: var(--left-position-start);
  } 
  to: {
    top: var(--top-position-end);
    left: var(--left-position-end);
  }
}

通过在根元素上使用 CSS 变量,您可以将其传递给 @keyframes 事件。

使用 CSS let ran = getRandomInt(99); let skew = ran + getRandomInt(10); root.style.setProperty('--top-position-end', `${ran}vw`); root.style.setProperty('--left-position-end', `${skew}vw`); leftbackground-color:{{1 使用随机放置的 div 查看以下工作示例}}rgb()(red, green, 使用 html:root 样式传递给 @keyframes 在 CSS 中。

blue
)
let root = document.documentElement;
let rain = document.querySelectorAll('.drop');

function getMaxInt(max) {
  return Math.floor(Math.random() * Math.floor(max));
}

function getMinMaxInt(min, max) {
  return Math.random() * (max - min) + min;
}
// set an interval to drop the div from randomly positioned view widths on the screen
setInterval(() => {
  let ran = getMaxInt(86);
  let skew = ran + getMaxInt(10);
  let circle = `${getMinMaxInt(3,15)}px`;
  root.style.setProperty('--keyframeLeftStart', `${ran}vw`);
  root.style.setProperty('--keyframeLeftEnd', `${skew}vw`);  
  root.style.setProperty('--animationDuration', `${ getMaxInt(2500)}ms`); 
  root.style.setProperty('--width', circle);
  root.style.setProperty('--height', circle);
  root.style.setProperty('--red', getMinMaxInt(100, 255));
  root.style.setProperty('--green', getMinMaxInt(100, 255));
  root.style.setProperty('--blue', getMinMaxInt(100, 255));
}, getMaxInt(3500))

答案 10 :(得分:0)

使用 JavaScript 在一次调用中设置 @keyframe,并使用它,使用 append()Object.assign()template strings

document.body.append(
  Object.assign(document.createElement("style"), {
    textContent: `@keyframes coolrotate { from { transform: scale(1, 1) translate(-0.1em, 0)} to { transform: scale(-1, 1) translate(0, 0) }} small { display: inline-block; font-size:2.3em; animation: 1s infinite alternate coolrotate } body {font-size: x-large}`
  }),
  Object.assign(document.createElement("span"), {
    innerHTML: `<span>c</span><small>o</small><span>o</span><small>L</small><small>...</small>`,
    style: "font-weight: 1000; font-size: 3.3em;"
  })  
)

答案 11 :(得分:0)

现在可以使用新的 Web Animations API 轻松实现这一点。超人。

它可能看起来像:

let anim = document.getElementById('foo').animate(
[
  { transform: `rotate(${A_DYNAMIC_VALUE})` }
], {
  duration: 3000 //Dunno if can be Infinite
});

// and later
anim.pause();

答案 12 :(得分:0)

通过使用 CSS 数据 URI 发现了一个简单的 JavaScript 想法。

解决方案

function addNewCSS(css_text) {
  css_text = encodeURIComponent(css_text);
  const url = `data:text/css,${css_text}`;
  const link = document.createElement("link");
  link.rel = "stylesheet";
  link.href = url;
  document.head.appendChild(link);
}

函数接受 CSS 代码作为文本并将其添加为样式。

工作

将 CSS 文本转换为 URI 编码形式(作为数据 URL 传递)。然后创建一个链接标签,以 href 为 url,关系为“样式表”(这里 rel 属性是必需的,如果不添加将不起作用)最后将链接标签附加到 head 标签。

示例

function addNewCSS(css_text) {
  css_text = encodeURIComponent(css_text);
  const url = `data:text/css,${css_text}`;
  const link = document.createElement("link");
  link.rel = "stylesheet";
  link.href = url;
  document.head.appendChild(link);
}

const duration = 1;
const colour = ["#2196F3", "#E91E63"];
const css_data = `
  @keyframes change{
    0% {
      background: ${colour[0]};
    }
    100% {
      background: ${colour[1]};
    }
  }
  body {
    animation: change ${duration}s linear infinite alternate;
  }
`;

addNewCSS(css_data);
<html>
  <head></head>
  <body>
    <h1>Wait to see JS adding background color animation</h1>
  </body>
</html>

结论

我没有在所有浏览器上测试过,但在 chrome 中工作,并且因为它被添加到 head 标签的末尾,所以它从 head 中的其他标签中获得优先权,如果您打算频繁更改值,而不是添加新的标签,尝试编辑之前添加的标签的 href