68

我需要旋转 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/

提前致谢

4

13 回答 13

66

您可以动态插入样式表规则以覆盖头部中以前的样式。这有助于避免为单个任务添加另一个库。

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);
于 2015-08-07T02:20:02.207 回答
46

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

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

然而,CSS 过渡可以给你带来的复杂性是非常有限的——一个包含多个步骤的动画很难实现。

这是 CSS @keyframe 动画旨在解决的问题,但它们没有提供过渡所提供的动态响应级别。

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

Link1 :一个生成带有许多小步骤的@-webkit-keyframe 动画的工具。这为无限选择缓动公式打开了大门。

Link2将它作为基础将对您有很大帮助,因为它提供了一个 UI 来创建动画并将其导出为 CSS 代码。

我想 这个 解决方案肯定对你有用。它用于动态关键帧

于 2013-08-28T07:26:01.323 回答
12

让我分享一个更新的(2019 年)答案。

是的,没有 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));
  }
}

请参阅使用 CSS 变量的 Codepen动态 CSS 动画演示

编辑:这也是一篇关于它的 CSS 技巧文章

于 2019-04-17T09:57:51.720 回答
11

亚历克斯格兰德的回答对一些关键帧非常有效。但是,假设您想一遍又一遍地动态添加关键帧,那么您的网页会很快变得非常滞后。要解决这个问题,只需停止创建新的 DOM 元素。相反,创建 1 个新的 DOM 样式表,然后将其与insertRule. 如果您想要更多关键帧(例如,如果您要为每个动画帧生成一个新的关键帧),那么您需要设置一个系统,在旧关键帧不再使用后将其删除。这是如何实现此类目标的良好开端。

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]直到IE10 才被支持。只是说...type = 'text/css'@keyframes

于 2017-05-10T23:23:44.953 回答
3

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

于 2018-02-06T07:46:15.330 回答
1

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

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

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

于 2019-01-19T22:11:02.000 回答
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/

于 2018-02-23T05:40:26.337 回答
1

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

:root {--variable-name:property;}这基本上是文档的根元素<html>。然后使用 JS 更改 CSS 根变量的值:

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

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

然后JS会喜欢这样的东西:

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

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

请参阅以下使用 CSS 随机放置 divleft并 使用html:root样式传递给CSS 中的@keyframes的工作示例。background-color:rgb()(red, green, 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))
* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

/* here we define some css variables for the document :root 
   essentially, these will be the first iteration of the elements style
   then JS will take voer and set the values from script */
:root {
  --keyframeTop: 0;
  --keyframeBottom: 98vh;
  --keyframeLeftStart: 2vw;
  --keyframeLeftEnd: 10vw;
  --animationDuration: 1s;
  --width: 5px;
  --height: 5px;
  --red: 100;
  --green: 100;
  --blue: 100;
}

body {
  width: 100vw;
  height: 100vh;
  background-color: #000;
}

#main {
  width: calc(100vw - var(--width));
  height: calc(100vh - var(--height));
  display: flex;
  justify-content: center;
  align-items: center;
  color: #fff;
}

.drop {
  width: var(--width);
  height: var(--height);
  border-radius: 50%;
  position: absolute;
  animation: dropping var(--animationDuration) ease-in infinite;
  top: var(--keyframeTop);
  left: var(--keyframeLeftStart);
  background-color: rgb(var(--red),var(--green), var(--blue));
}

@keyframes dropping {
  0% {
    top: var(--keyframeTop);
    left: var(--keyframeLeftStart);
    background-color: rgb(var(--red),var(--green), var(--blue));
  }
  50% {
    background-color: rgb(var(--green),var(--blue), var(--red));
  }
  100% {
    top: var(--keyframeBottom);
    left: var(--keyframeLeftEnd);
    background-color: rgb(var(--blue),var(--red), var(--green));
  }
}
<div id="main">
    <div class="drop"></div>
</div>

于 2021-01-11T06:55:53.933 回答
1

使用 JavaScript 在一次调用中设置@keyframe,并使用append()Object.assign()模板字符串来使用它。

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

于 2021-05-10T03:53:30.150 回答
1

这现在可以通过新的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();
于 2021-05-18T13:10:08.447 回答
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以前添加的标签。

于 2021-07-27T05:45:51.543 回答
0

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

此外,正如其他人所建议的那样,如果您需要创建许多不同的动画,那么最好重用一个<style>标签,而不是创建多个标签并使用CSSStyleSheet.insertRule().

最后,如果你可以使用 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>

甚至更好:

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>

于 2018-09-11T17:39:39.093 回答
0

user7892745 对我不起作用,需要一些小调整

1° "pos" 不明白 wot 应该是什么,但控制台日志说 "undefined" 所以我删除了 " , pos"

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

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 marquee cuold 似乎很容易做同样的事情,但效果不佳,

于 2017-11-30T09:25:30.110 回答