IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    CSS Animations vs Web Animations API

    Airen发表于 2017-05-09 12:23:31
    love 0

    上周,我写了一篇关于如何使用CSS制作bitsofcode logo的动画效果。之后收到一些建议,尝试比较一下CSS动画和Web Animations API。所以今天写了这篇文章。

    Web Animations API简介

    和上周一样,我开始介绍Web Animations API。 Web Animations API为开发人员提供了一种方式,使用JavaScript可以直接操作浏览器的动画引擎。

    如果你没有从示接触过Web Animations API的话,这篇文章是一篇很好的入门课程。除此之外,在站上已经有很多相关的教程,感兴趣的同学,可以点击这里进行阅读。

    创建一个动画

    使用Web Animations API创建一个动画,可以使用Element.animate()函数,这个函数接受两个参数keyframes和options。

    element.animate(keyframes, options);  
    

    keyframes

    keyframes对象代表动画事件的时间线(Timeline)。有两种方法来写这个对象。为了说明他,我们来创建一个grow动画,这个动画的效果是把元素放大两倍。使用CSS的@keyframes可以这样写:

    @keyframes grow {
        0% {
            transform: none;
        }
        100% {
            transform: scale(2);
        }
    }
    

    第一种写keyframes的方法是把它声明成一个单独的对象。对象中的每个键(key)代表我们想要动画的CSS属性。每个键的值(values)是一个数组,数组里的值是我们想要动画的CSS属性值。数组中的每个值代表动画时间轴中每一个点的。

    const growKeyframes = {  
        transform: ['none', 'scale(2)'];
    }
    

    第二种写keyframes的方法是把它写成一个数组。数组中的每一项代表时间线上的一个点,数组中的每个值是想要动画的CSS的属性和值。

    const growKeyframes = [  
        { transform: 'none' },
        { transform: 'scale(2)' }
    ]
    

    默认情况下,每个点在时间轴上是等距的。例如,如果我们的时间轴上有五个点,那么每个点之间的动画过渡时间都是同样的,都是20%。

    如果我们想改变时间,给keyframes写第二个值,给这个值设置offset属性,这个属性接受0到1之间的数字,这个数值就是代表CSS的@keyframes中的百分比值:

    @keyframes alteredGrow {
        0% { transform: none; }
        10% { transform: scale(1.5); }
        30% { transform: scale(1.9); }
        100% { transform: scale(2); }
    }
    

    上面CSS的@keyframes我们可以写成:

    const alteredGrowKeyframes = [  
        { transform: 'none' },
        { transform: 'scale(1.5)', offset: 0.1 }
        { transform: 'scale(1.9)', offset: 0.3 }
        { transform: 'scale(2)' }
    ]
    

    options

    animate()函数的第二个参数是一个对象,该对象允许我们指定所有适用于动画CSS属性。总共有九个选项:

    • id:一个独特的参考动画(设置或者获取动画的id名)
    • delay:指定延迟播放动画时间,对应CSS的animation-delay属性
    • duration:指定动画持续播放时间,对应CSS的animation-duration属性
    • iterations:指定动画循环播放次数,对应CSS的animation-iteration-count属性
    • direction:指定在时间轴哪个方向运行动画,对应CSS的animation-direction属性
    • easing:指定动画之间的转换方式,对应CSS的animation-timing-function属性
    • fill:指定元素动画开始和结束值,对应CSS的animation-fill-mode属性
    • endDelay:指定一个时间延迟后的动画
    • iterationStart:指定第n次动画播放的开始时间

    例如,让我们来调用alteredGrow动画,使用CSS的动画属性来控制,比如动画播放持续3s,延迟2s开始播放,动画的播放方向alternate,并且无限次播放:

    .animated-element {
        animation-name: alteredGrow;
        animation-duration: 3s;
        animation-iteration-count: infinite;
        animation-direction: alternate;
        animation-delay: 2s;
    }
    

    使用Web Animations API,我们可以指定同样的参数:

    const alteredGrowOptions = {  
        duration: 3000,
        iterations: Infinity,
        direction: 'alternate',
        delay: 2000
    }
    

    使用动画

    在需要运用动画的元素上调用animate()函数,并且给它指定keyframes和options参数:

    const element = document.querySelector('.animated-element');  
    element.animate(alteredGrowKeyframes, alteredGrowOptions);  
    

    一旦函数被调用,动画就会自动播放。然后我们可以通过play()和pause()方法来控制动画的开始和停止:

    const element = document.querySelector('.animated-element');  
    const myAnimation = element.animate(alteredGrowKeyframes, alteredGrowOptions);
    
    myAnimation.pause();  
    myAnimation.play();  
    

    浏览器兼容性

    bitsofcode Logo动画效果

    下面视频录制了使用CSS动画制作的bitsofcode Logo的动画效果。

    创建Timeline

    回顾一下,Logo中动画步骤(Logo从o字分开,"bitso"):

    • 向左移动
    • 回到中间
    • 停在中间(等右边部分向右移动)
    • 移到左边
    • 旋转
    • 慢慢增加旋转
    • 回到不旋转位置
    • 回到中间

    基于这些步骤,左边部分可以创建一个Timeline:

    基于这个时间线,Web动画中的keyframes对象每步对应的样式如下:

    const logoSectionLeftKeyframes = [  
        { transform: 'none' },
        { offset: 0.125, transform: 'translateX(-15px)' },
        { offset: 0.25, transform: 'none' },
        { offset: 0.5, transform: 'none' },
        { offset: 0.625, transform: 'translateX(-15px)' },
        { offset: 0.67, transform: 'translateX(-15px) rotate(-10deg)' },
        { offset: 0.72, transform: 'translateX(-15px) rotate(-10deg)' },
        { offset: 0.82, transform: 'translateX(-15px) rotate(-15deg)' },
        { offset: 0.875, transform: 'translateX(-15px)' },
        { transform: 'none' }
    ];
    

    因为需要使用offset属性,所以我决定使用数组的格式来定义keyframes。

    设置参数

    参数设置很简单,动画持续播放的时间是3s,并且是无限次数的播放。

    const logoSectionOptions = {  
        duration: 3000,
        iterations: Infinity
    };
    

    运用动画

    Web Animation API应用动画要比CSS Animation更繁琐。主要是因为Logo在鼠标悬浮或得到焦点时才有动画效果。正如我提到的,默认情况下,Web动画动行就创建了动画。

    为了解决这一问题,我必须先创建动画,然后通过eventListeners来监听动画的播放或暂停。此外,由于这个动画应用于每个字母,我不得不一次处理多个动画。下面的代码就是如何让动画执行:

    // Array to store all animations
    const animations = [];
    
    function playLogoAnimation() {  
        animations.map((animation) => animation.play())
    }
    
    function pauseLogoAnimation() {  
        animations.map((animation) => {
            animation.pause();
            animation.currentTime = 0; // Reset animation to start state
        })
    }
    
    function createLogoAnimation() {  
        const logoSectionLeftEls = Array.from( document.querySelectorAll('.logo-section-left') );
        logoSectionLeftEls.forEach((el) => animations.push(el.animate(logoSectionLeftKeyframes, logoSectionTiming)))
    
        // Animation for middle and right sections here …
    
        // Immediately pause animation once created
        pauseLogoAnimation();
    }
    
    createLogoAnimation();
    
    // Event listeners to play or pause animation
    const siteTitleLink = document.querySelector('.site__title a');  
    siteTitleLink.addEventListener('mouseover', playLogoAnimation);  
    siteTitleLink.addEventListener('mouseout', pauseLogoAnimation);  
    siteTitleLink.addEventListener('keyup', (e) => {  
        if ( e.keyCode === 9 ) playLogoAnimation();
    });
    siteTitleLink.addEventListener('keydown', (e) => {  
        if ( e.keyCode === 9 ) pauseLogoAnimation();
    });
    

    最后整个效果如下:

    CSS Animations VS Web Animation API

    和其他事情一样,肯定会被问及是否使用CSS或JavaScript动画,很大程度上取决于动画的细节。作为一般规则,CSS动画应用小的场景,与UI相关的动画,比如提示信息(tooltip)。Web Animation API应该留给更高级的效果。这就是我认为选择CSS动画或JavaScript动画的一般规则。

    性能

    CSS和JavaScript动画的性能主要取决于动画属性。一般来说,我建议只在动画中使用transform或opacity属性,因为这些动画可以在不同的线程上执行,也就是在浏览器的主线程上执行。

    改变transform不会触发任何几何形状的变化或重绘,这是非常好的一点。这意味着这些操作可能可以人工启动GPU——CSS Triggers

    自从我的动画只使用transform属性,我在这两个方法之间无法看到任何显著的性能差异。使用Firefox的DevTools,可以测量两个动的帧率,他们是完全相同,都在60FPS,即使启用了主线程的动画。

    我没办未能找到更多的方法来衡量这两个方法之间的性能。如果你知道任何更好的方法,请在下面的评论中与我们分享。

    开发经验

    在这种情况下,我个人发现CSS动画比使用Web Animation API更容易,这主要是因为后者额外的工作主要花在了动画的播放或暂停。如果要做一个更为复杂的动画,例如游戏,Web Animation API肯定是更好,然而,对于这个示例,我认为CSS动画是更简单的。

    本文根据@Ire Aderinokun的《CSS Animations vs the Web Animations API: A Case Study》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:https://bitsofco.de/css-animations-vs-the-web-animations-api/。

    大漠

    常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。

    如需转载,烦请注明出处:http://www.w3cplus.com/animation/css-animations-vs-the-web-animations-api.html

    译文
    Animation
    Web动画
    Web动画API
    CSS3


沪ICP备19023445号-2号
友情链接