Skip to content

Latest commit

 

History

History
100 lines (52 loc) · 8.83 KB

动画顺畅的10条原则.md

File metadata and controls

100 lines (52 loc) · 8.83 KB

原文链接

image

自从去年我们发布了Gyroscope之后,好多人都问我们在代码中引用了哪些动画库。我们打算把这些动画库开源,但这些并不是让动画流畅的黑科技。

我们不想让别人觉得依靠一些特殊的插件就能够神奇地解决动画卡顿。在很大程度上,我们仅仅是站在浏览器GPU以及CSS3这些巨人的肩膀上而已。

对于动画,除了花费大量的时间跟精力不断测试以及优化他们,其它并没有什么银弹。在很多年的试验以及不断尝试浏览器的表现后,我们发现了一些能够让动画顺畅的代码技巧和设计原则。利用这些技巧,你网页里的动画应该可以在现代浏览器的PC端以及移动端看起来更加顺滑,更重要的是,这些技巧很容易实现。

image

技术以及实施的一些细节对于每个人来说,可能会有轻微的不同,但主要的原则在大部分场景都应该是适用的。

什么是动画?

动画在互联网出现之前就已经存在,做好动画是可以花一生去追求的事。然而,在互联网领域做动画,存在一些不同的限制以及挑战。

想要60fps动画能够流畅展示,每一帧的渲染时间都必须在小于16ms!这可不是一个长的时间段,所以,为了动画流畅,我们需要寻找非常有效率的方法去渲染每一帧。

image

image

image

现在有很多方法在网页上面实现动画。例如,在互联网之前,幻灯片就是一种实现动画的途径,它利用在一秒钟之内快速展示多个手工绘制的只有轻微不同的图片来创建动画。

Twitter最近就是使用了这种方法来实现它们的新的“心形”动画,通过每一帧展示不同图像的变换来实现。

image

这个动画可以通过一系列不同的元素各自变化实现这个效果,或者有可以用 SVG,但是那样就太复杂了,而且也不会这么顺畅。

image

在很多情况下,你会使用CSStransition属性在元素变化时来自动实现动画。这项技术也有另一个被人熟知的名字tweening-在两个不同的值之间进行变化。它无需设置所有的逻辑就可以很容易中断或者撤销动画的执行。这是最理想的set and forget风格动画,比如,介绍页的动画(intro sequences)等等,或者一些如hover的简单交互。

推荐阅读:All you need to know about CSS Transitions

image

另一方面,基于帧的CSS动画属性也适用于重复的背景细节变化。例如,Gyroscopelogo标志里周期性不间断变化的时钟,除此之外,能够利用CSS animation语法的是齿轮齿数比。

好了,废话不多说了,下面来分享一些能够很好的提高动画表现的建议。

1.除了opacitytransform,不要改变任何属性

即使你认为这样它可能还好,但是别这么做

仅这个简单的建议就能够让你实现80%动画流畅运行,包括移动端。你可能之前已经听说过这个了-这不是我的原创但是它很少被遵循。它在web圈就如同“好好吃饭,积极锻炼,早睡早起”一样,听起来很简单,很好,但是你很可能会忽略它。

一旦你习惯了按照这个建议去写动画,你就如同在康庄大道上行走,自然而然的按照这个建议去做,但是如果你之前习惯利用修改传统的CSS属性来实现动画,可能这个建议对你而言就是一次蹦极。

例如,你想把某个元素变小,你可以利用transform: scale()而不是改变其宽度。如果你想要让这个元素在网页上“四处溜达”一下,除了设置一大堆乱成一坨的marginpadding不停变换--需要在每一帧重绘整个页面--你仅需要使用一个简单的transform: translateX or transform: translateY

为什么这样做会有效?

对人而言,改变widthmargin或者其他属性看起来并不是什么大问题-有可能这样做更简单-但在计算机的世界里天壤之别,这个做法非常,非常糟糕。

浏览器制作团队花费了很大的精力来优化这些操作。transform能够在不重绘页面的基础上很好的利用图形显卡的性能,达到很棒的动画效果。

首次加载页面的时候,你可能会抓狂,利用图片或者阴影在每一个角落上面做一个遮盖,甚至你可以不顾一切的做一个动态模糊。如果这些只发生一次的话,多余的几毫秒渲染时间无关紧要。但是,一旦内容渲染完成了,你不会想再来一次。

推荐阅读:Moving elements with translate (Paul Irish)

2.在空白处隐藏内容

设置 opacity 为 0 以及 pointer-events: none 来隐藏元素

这个做法可能在一些浏览器上面存在兼容性问题,但如果你仅仅需要适配webkit内核或者其他的现代浏览器,你会发现你无需在兼容性上浪费时间。

很久以前,那时候动画仍然采用 jQueryanimate() 方法,很多切换效果的复杂之处是在恰当的时机设置display:none以及display:block。太早了,动画还未结束,太晚了页面上就只剩下一堆透明度为0的不可见的内容。每次当动画结束之后都需要设置callback函数去“擦屁股”。

这个CSS pointer-events属性(不常用,但是它已经存在很长时间了)最基本的功能就是让元素对于点击或者其它交互不做点击,就好像那些元素不存在一样。这个属性值可以很简单的通过CSS设置来控制,在任何条件下不会打断动画或者影响渲染、可见度。

opacity:0这个属性与display:none具有同样的效果,但不会触发重绘。当需要隐藏某个元素的时候,我经常会设置opacity0并且将pointer-events设置为none,之后,我就不管它了,让它自己去一边玩了。

对于设置了position:absolute的元素,可以确信这样做的效果更好,因为绝对定位的元素不会对页面上的其它元素有影响。

同时,这样做还给你留有余地。当一个元素完全出现一秒钟之后,它才变成可点击或者才能覆盖其它元素,或者只有当其完全出现,它才能点击,这些情况下不需要将时间设置的完美无缺。

3.不要同时对多个元素设置动画

如果一定要运行多个动画,让它们排队吧

只有一个简单的动画时,效果会很顺畅,但是如果同时有很多一起运行的话,动画就会变得一团糟。仅仅只写一个简单的能够流畅运行的demo很容易,但想要保证网站所有的动画都能流畅运行,难度就不是一个数量级的了。因此,安排动画“排队”就很重要了。

你需要错落的安排动画的运行时间,保证它们不在同一时间点运行。一般而言,2-3个动画同时运行不会出现明显的卡顿。尤其是在它们开始的时间略有不同的情况下。但是超过一定的个数,动画就可能出现卡顿的情况。

理解“排队”这个词的含义很重要,除非你的页面上面只有一个DOM元素。它看起来只是舞蹈领域的一个专有词汇,但它在动画交互领域也一样重要。元素需要在合适的时间以及合适的方向出现。即使他们相互之间分离,仍需要给人们一种良好的观感。

Google的material design 对于这个主题有一些自己的建议。虽然不是实现“动画排队”的唯一法门,但其中总有一些你可以去思考并且尝试的。

image

推荐阅读:Google Material Design · Motion

4.适当的增加过渡时间来更好的安排动画“排队”

队列动画非常重要,只有经过很多次的试验以及测试,动画才能恰如其分,让我感觉良好。但是,实现动画队列的代码没必要特别复杂。

我经常通过在父元素(大多数时候是 body)改变一个 class 来触发一系列动画,不同的动画延时保证了动画在恰当的时机展示。