如何使用JavaScript控制CSS Animations(动画)和Transitions(过渡)

Zach邮件跟我说,上Stack Overflow这类的论坛,他经常碰到一些关于JavaScript控制CSS 动画的问题,又提供给我几个例子。我很久就打算写一些关于这方面的文章,所以很高兴让Zach提出来并促使我写了这个教程。

有时候WEB开发人员认为CSS的动画比JavaScript的动画更难理解。虽然CSS动画有其局限性,但它的性能比大多数JavaScript库更加高效,因为它可以借助硬件加速啊!其效果绝对可以超出我们的预期。

CSS animations和transitions再加上点JavaScript就可以实现硬件加速动画,而且其交互效果比大多数JavaScript库更高效。

So,让我们快点开始吧!小伙伴们都等不及了!

注意:Animations(动画)和Transitions(过渡)是不同的

CSS Transitions(过渡)被应用于元素指定的属性变化时,该属性经过一段时间逐渐的过渡到最终需要的值;而CSS Animations(动画)只是在应用时执行之前定义好的操作,它提供更细粒度的控制。

在这篇文章中,我们将分别针对上述内容进行讲解。

控制CSS Transition(过渡)

 

在编程论坛中,关于transition(过渡)的触发和暂停有无数的疑问。使用JavaScript可以很容易的解决这些疑问。

触发元素的transiton(过渡),切换元素的类名可以触发该元素的transition(过渡)

暂停元素的transition(过渡), 在你想要暂停过渡点,用getComputedStyle和getPropertyValue获取该元素相应的CSS属性值,然后设置该元素的对应的CSS属性等于你刚才获取到的CSS属性值。

以下是该方法的一个例子。

执行效果:http://cdpn.io/GokAm

同样的技术可以用在更高级的方法上。下面的例子也是通过改变类名来触发元素的transition(过渡),但这次可以跟踪当前的缩放率。

执行效果:http://cdpn.io/FIlHe

注意我们这次改变的是background-size的值。有许多不同的CSS属性可以应用到过渡和动画中,这些属性通常具有数值或颜色值。关于CSS transitions(过渡),Rodney Rehm也写了一篇非常不错的文章,这里可以访问到

使用CSS“回调函数”

 

一些最有用但鲜为人知javascript技巧,就是利用监听Dom事件控制CSS transitions(过渡)和animations(动画)。如:与animations(动画)相关的animationEnd,animationStart和animationIteration;与transitions(过渡)相关的transitonEnd。你可能已经猜到它们是做什么的。这些动画事件分别是在元素的动画结束时,开始时,或者完成一次迭代时触发。

目前使用这些事件还需要添加浏览器前缀,所以在这个演示中,我们使用由Craig Buckler开发的叫PrefixedEvent的方法。该方法的参数有element(元素),type(类型)和callback(回调)来实现跨浏览器的兼容。这里是他的一篇文章使用JavaScript捕获CSS animations(动画)。这里是另一篇关于通过判断动画名称来判断触发哪个事件。

这个演示想实现当鼠标悬浮时停止动画,并放大心型图案。

执行效果:http://cdpn.io/rmDdx

纯CSS版本在鼠标悬停时会跳一下,除非你在恰当的时机鼠标移上去,不然它会在扩大到最终悬停状态之前先跳到一个特定状态。JavaScript版本就非常流畅,它在应用新的放大状态之前先让动画完成,这样鼠标悬停时就不会跳动。

控制CSS Animation(动画)

 

就像我们刚刚了解到的,我们可以看到与元素动画相关的事件:animationStart,animationIteration,animationEnd。但是如果我们想改变CSS animation(动画)执行过程中的动画,还需要一点技巧!

animation-play-state属性

当你想在动画执行过程中暂停,并且接下来让动画接着执行。这时CSS的animation-play-state属性是非常有用的。你可以可以通过JavaScript像这样更改CSS(注意你的前缀):


1

2

element.style.webkitAnimationPlayState = "paused";

element.style.webkitAnimationPlayState = "running";

然而当使用animation-play-state让CSS 动画暂停时,动画中的元素变形也会以相同的方式被阻止。你不能使这种变形暂停在某个状态,使它变形,使它恢复,更不用期望它能从新的变形状态中恢复到流畅运行。为了实现这些控制,我们需要做一些更复杂的工作。

获取当前keyvalue的百分比

不幸的是,在这个阶段没有办法获得当前CSS动画关键帧的“完成百分比”。最好的获取近似值的方法是使用setInterval 函数在动画过程中迭代100次。它的本质是:动画持续的时间(单位是毫秒)/100。例如,如果动画时长4秒,则得到的setInterval的执行时间是每40毫秒(4000 / 100)。

这种做法很不理想,因为函数实际运行频率要远少于每40毫秒。我发现将它设为39毫秒更准确。但这个也不是好实现,因为它依赖于浏览器,并非所有浏览器下都能得到很完美效果。

获取当前动画的CSS属性值

在理想的情况下,我们选择一个使用CSS动画的元素,删除该元素当前动画再给它添加个新的动画,让它可以从当前状态开始新的动画。但是现实情况却很复杂。

下面我们就有一个演示,用来测试获取和改变CSS动画”中间流”的技术。该动画让一个元素沿一个圆形路径移动,起始位置在圆形的顶部中心(或称为“十二点”)位置。当按钮被单击时,元素的起始位置变成元素当前移动到的位置。元素会沿着之前相同的路径继续移动,只是现在“起始”的位置变成了你按下按钮时元素移动到的位置。通过在动画的第一关键帧把元素的颜色变成红色,来表示元素动画起始点位置发生了改变。

执行效果:http://cdpn.io/GwBJa

相同的概念用在StackOverflow的这个例子中。

我们需要很深入才能完成!我们要进入的样式表本身找到原有动画。

你可以用document.styleSheets来获取与页面关联的样式表的集合,然后通过for循环取得具体的样式表。以下是如何使用JavaScript来找到一个特定动画值的CSSKeyFrameRules对象:


1

2

3

4

5

6

7

8

9

10

11

function findKeyframesRule(rule){

var ss = document.styleSheets;

for(var i = 0;i < ss.length;++i){

for(var j = 0;j<ss[i].cssRules.length;++j){

if(ss[i].cssRules[j].type == window.CSSRule.WEBKIT_KEYFRAMES_RULE && ss[i].cssRules[j].name == rule){

return ss[i].cssRules[j];

}

}

}

return null;

}

我们一旦调用上面的函数(例如 var keyframes= findKeyframesRule(anim)),就可以通过keyframes.cssRules.length获得该对象的动画长度(这个动画中关键帧的总数量)。然后使用JavaScript的.map方法把获得到的每个关键帧值上的“%”过滤掉,这样JavaScript就可以把这些值作为数字使用。


1

2

3

4

5

6

7

8

9

10

11

12

// Makes an array of the current percent values

// in the animation

var keyframeString = [];

for(var i = 0; i < length; i ++)

{

keyframeString.push(keyframes[i].keyText);

}

// Removes all the % values from the array so

// the getClosest function can perform calculations

var keys = keyframeString.map(function(str) {

return str.replace(‘%‘, ‘‘);

});

这里keys是一个包含所有动画关键帧数值的数组。

改变实际的动画(终于!)

在循环动画演示过程中,我们需要两个变量:一个用来跟踪从最近的起始位置开始移动了多少度,另一个用来跟踪从原来的起始位置开始移动了多少度。我们可以使用setInterval函数(在环形移动度数时消耗的时间)改变第一个变量。然后我们可以使用下面的代码,当单击该按钮时更新第二个变量。


1

2

3

4

5

totalCurrentPercent += currentPercent;

// Since it‘s in percent it shouldn‘t ever be over 100

if (totalCurrentPercent > 100) {

totalCurrentPercent -= 100;

}

然后我们可以使用以下函数,在之前我们获得的关键帧数组里,找出与当前总百分比值最接近的关键帧值。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

function getClosest(keyframe) {

// curr stands for current keyframe

var curr = keyframe[0];

var diff = Math.abs (totalCurrentPercent - curr);

for (var val = 0, j = keyframe.length; val < j; val++) {

var newdiff = Math.abs(totalCurrentPercent - keyframe[val]);

// If the difference between the current percent and the iterated

// keyframe is smaller, take the new difference and keyframe

if (newdiff < diff) {

diff = newdiff;

curr = keyframe[val];

}

}

return curr;

}

要获得新动画第一关键帧的位置值,我们可以使用JavaScript的.IndexOf方法。然后我们根据这个值,删除原来的关键帧定义,重新定义该关键帧。


1

2

3

for (var i = 0, j = keyframeString.length; i < j; i ++) {

keyframes.deleteRule(keyframeString[i]);

}

接下来,我们需要把圆的度数值转换成相应的百分比值。我们可以通过第一关键帧的位置值与3.6简单的相乘得到(因为10 0 * 3.6 = 360)。

最后,我们基于上面获得变量创建新的规则。每个规则之间有45度的差值,是因为我们在绕圈过程中拥有八个不同的关键帧,360(一个圆的度数)除以8是45。


1

2

3

4

5

6

7

8

9

10

11

// Prefix here as needed

keyframes.insertRule("0% {

-webkit-transform: translate(100px,100px) rotate(" + (multiplier + 0) + "deg)

translate(-100px,-100px) rotate(" + (multiplier + 0) + "deg);

}");

keyframes.insertRule("13% {

-webkit-transform: translate(100px,100px) rotate(" + (multiplier + 45) + "deg)

translate(-100px,-100px) rotate(" + (multiplier + 45) + "deg);

}");

...continued...

然后我们通过setInterval重置当前百分比值来使它可以再次运行。注意上面使用的是WebKit前缀,为了使它兼容更多的浏览器,我们需要做一些UA的嗅探来确定采用哪个前缀:


1

2

3

4

5

6

7

8

9

10

11

12

13

// Gets the browser prefix

var browserPrefix;

navigator.sayswho= (function(){

var N = navigator.appName, ua = navigator.userAgent, tem;

var M = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);

if(M && (tem = ua.match(/version\/([\.\d]+)/i))!= null) M[2] = tem[1];

M = M? [M[1], M[2]]: [N, navigator.appVersion,‘-?‘];

M = M[0];

if(M == "Chrome") { browserPrefix = "webkit"; }

if(M == "Firefox") { browserPrefix = "moz"; }

if(M == "Safari") { browserPrefix = "webkit"; }

if(M == "MSIE") { browserPrefix = "ms"; }

})();

如果你想进一步研究,可以访问Russell Uresti在StackOverflow上的帖子相应的案例

Animations(动画)转成Transitions(过渡) 

正如我们所看到的,使用JavaScript可以很方便的操作CSS transitions(过渡)。如果使用CSS animations(动画)最终没能得到想要的结果,你可以试着把它变成css transitions(过渡)来实现。从CSS代码来看他们大约有相同的代码量,但使用transiton可以更容易地设置和编辑。

将CSS animations(动画)转换成CSS transitions(过渡)的最大问题是,当我们把animation-iteration转换成与之等效的transition命令时,Transitons(过渡)没有直接等效命令。

关于我们的旋转演示,有一个小技巧就是用x来分别乘以transition-duration和rotation(译者:分别包括X轴和Y轴的旋转值)。然后你需要使用样式类来触发这个动画,因为如果你在元素上直接改变这些属性,将不会有过渡效果。你需要给元素添加类名来触发过渡(模拟动画)。

在我们的例子中,我们在页面加载时实现:

执行效果:http://cdpn.io/IdlHx

利用CSS矩阵

你也通过CSSMatrix来操作CSS animations(动画)。比如:


1

2

var translated3D =

new WebKitCSSMatrix(window.getComputedStyle(elem, null).webkitTransform);

但是这个过程可能有些混乱,尤其对于那些刚刚开始使用CSS animations(动画)的。

想获取更多CSS矩阵的信息,请参阅文档(虽然帮助不太大),这个工具可以让你操作矩阵的值,或关于这个主题的文章

重置CSS animations(动画)

实现这个技巧的方法可以从CSS Tricks找到。

动动脑筋

 

在开始编码前,就思考和规划过渡或动画如何执行,应该是减少你的问题和达到你想要的效果的最佳途径。好过你在遇到问题时google搜索解决方案!虽然在这篇文章中总结的技术和技巧,不一定是你在项目中创建动画的最佳方案,但值得你尝试着了解一下(师兄我也只能帮到这里了……)。

比如这个小例子仅通过html和css就解决了问题,你可能开始会想着使用JavaScript去解决。

我们想让一个不停旋转的图形当鼠标悬停时反方向旋转。你可能跳过这篇文章讲解的内容直接使用animationIteration事件来实现这个动画。然而,一个更有效更好的方案是是使用CSS和添加内容元素。

技巧是获取旋转图形旋转速度x,当鼠标悬停时,让其父元素以2倍x的速度反方向旋转(在相同的位置)。两个方向的旋转相互作用,最终得到想要的反向旋转的效果。

执行效果:http://cdpn.io/sFnyD

相同的概念用在StackOverflow的这个例子中。

相关链接

你可能会感兴趣的相关东东。

Animo.js – 用于管理CSS动画的强大小工具

Thank God We Have A Specification! – Smashing Magazine上的关于transition技巧的文章

总结

1. getComputedStyle 对于操作CSS transitions(过渡)很有帮助

2. transitionEnd及其相关事件对于使用JavaScript操作CSS transitions(过渡)和animations(动画)非常有帮助

3. 通过使用JavaScript获取样式表可以更改当前CSS animation的值,但操作比较复杂。

4. 通常情况下使用JavaScript操作CSS transitions(过渡)比操作CSS animations(动画)要更容易。

5. 处理CSS矩阵比较痛苦,尤其对于初学者来说。

6. 思考应该做什么和规划如何做,是动画编码的关键。

时间: 2024-10-19 13:39:10

如何使用JavaScript控制CSS Animations(动画)和Transitions(过渡)的相关文章

使用javascript和css模拟帧动画的几种方法浅析

我们平时在开发前端页面的时候,经常会播放一段帧序列.这段帧序列就像gif图片那样,反复循环播放.那大家可能会说,直接用gif图片就好了,干嘛还去模拟呢?那是因为要做得更加灵活,我们要做到以下几点: 1.我们希望这段帧动画只循环播放所指定的次数. 2.我们希望帧动画结束的瞬间执行某种操作.这个在游戏中大量存在. 3.我们想自如的控制播放的速度. 4.我们想尽可能让这个帧动画的实现方式兼容大部分浏览器,在移动和pc端都能运行良好. 有了以上四点要求,那就不是gif图片所能完成的了.下面,我们先探讨有

CSS--使用Animate.css制作动画效果

一 使用Animate.css动画 // 通过@import引入外部CSS资源; // 引入线上图片及JS文件; // 通过更改CSS类名生成不同类型的CSS3动画;   1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="utf-8"> 5 </head> 6 <style> 7 /* Animate.css GitHu

第四十二课:基于CSS的动画引擎

由于低版本浏览器不支持css3 animation,因此我们需要根据浏览器来选择不同的动画引擎.如果浏览器支持css3 animation,那么就使用此动画引擎,如果不支持,就使用javascript的动画引擎. 首先,我们看一下判定条件,方便切换.前面说过,浏览器把所有事件类型的构造器放在window上,只不过不可遍历.我们用Object.getOwnPropertyNames(window),可以得到window对象中的所有属性,然后再filter一下,就能得到所有的事件构造器了.最后,我们

JS 控制CSS样式表

JS控制CSS样式,首先得确定一点,CSS与HTML页面的链接方式,因为CSS有3种与HTML页面结合的方式,不同的方式也会产生不同的结果. 下面先记录一下JS控制CSS所使用的方法. 1.使用javascript更改某个css class的属性... 1 <style type="text/css"> 2 .orig { 3 display: none; 4 } 5 </style> 你想要改变把他的display属性由none改为inline. 解决办法:

javaScript的一些奇妙动画

     今天我给大家讲一下JavaScript在实现一些动画时所用的一些方法以及需要注意的地方. 显示与隐藏动画效果 show()方法: show()方法会动态地改变当前元素的高度.宽度和不透明度,最终显示当前元素,此时元素的css属性display恢复为除了none之外的初始值. 其语法结构为:jQuery对象.show(duration,[fn]); 其中要注意当参数duration表示动画效果运行的时间,可以使用关键字slow.normal和fast,分别对应时间长度0.6秒.0.4秒和

Html,JavaScript和CSS的关系

Html,JavaScript和CSS的关系 1. HTML是网页内容的载体.内容就是网页制作者放在页面上想要让用户浏览的信息,可以包含文字.图片.视频等. 2. CSS样式是表现.就像网页的外衣.比如,标题字体.颜色变化,或为标题加入背景图片.边框等.所有这些用来改变内容外观的东西称之为表现. 3. JavaScript是用来实现网页上的特效效果.如:鼠标滑过弹出下拉菜单.或鼠标滑过表格的背景颜色改变.还有焦点新闻(新闻图片)的轮换.可以这么理解,有动画的,有交互的一般都是用JavaScrip

css实现动画功能

在CSS中动画功能其实可以说是很强大的,在网页中加载速度很快,他的功能特效可以一千变万化,做不到只有想不到的,当然前提是你要掌握在CSS3上面的各种标签,今天带来了我在课程练习中的动画的3D动态旋转.代码如下:    <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html        PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

JavaScript 操作CSS

JavaScript 操作CSS 关于CSS的介绍不是本文的内容范围,本文主要介绍如何使用JavaScript操作CSS. 1. 使用JavaScript操作Inline Styles 所有的文档元素都有style属性,我们可以通过直接操作style属性来修改相关元素的样式. 需要注意的是style属性的值并不是一个string对象,而是一个CSSStyleDeclaration对象. 我们可以通过如下方式设置style属性的值. e.style.fontSize = "24pt";

JavaScript强化教程——jQuery动画

本文为 H5EDU 机构官方 HTML5培训 教程,主要介绍:JavaScript强化教程 —— jQuery动画 jQuery 动画 - animate() 方法 jQuery animate() 方法用于创建自定义动画. 语法:$(selector).animate({params},speed,callback);必需的 params 参数定义形成动画的 CSS 属性. 可选的 speed 参数规定效果的时长.它可以取以下值:"slow"."fast" 或毫秒