给过渡和动画加上缓动效果是一种常见的手法(好比具备回弹效果的过渡过程)是一种流行的表现手法,可让界面显得更加生动和真实:在现实世界中,物体A点到B点每每也是不彻底匀速的css
以纯技术的角度来看,回弹效果是指当一个过渡达到最终值时,往回到一点,而后再次回到最终值,如此往复一次或者屡次,并逐渐收敛,最终稳定在最终值。有至关的多JavaScript类库能够建立动画,且内置回弹效果等其余缓动效果。可是眼下,咱们其实已经不须要借助脚原本实现过渡和动画了。不过,在CSS中实现回弹效果的最佳方式是什么呢?html
咱们的第一感受可能就是使用css动画,而且设置以下关键帧:函数
@keyframes bounce{ 60%,80%,to{transform:translateY(350px);} 70%{transform:translateY(250px);} 90%{transform:translateY(300px);} }
相信咱们都作过这样的事,可是咱们跑一遍这个动画,会发现它显示的及其不真实,主要缘由在于,每当这个小球方向改变时,她得移动过程都是持续加速的,这看起来很不天然。缘由其实就是由于它的调速函数在关键帧的衔接都是同样的
工具
全部的过渡和动画之间都是跟一条曲线有关的,这条曲线指定了动画过程在整段时间中是如何推动的
。学习
若是不指定调速函数,就是获得一个默认值。可是这个默认值
并非咱们想象中的匀速效果,而是:优化
注意,当时间进行到一半时,这个过渡已经推动到80%.动画
说到调速函数
,咱们很天然联系到了css内置的缓动曲线和贝塞尔曲线。spa
不管是在animation/transition
简写属性中,仍是在animation-timing-function/transition-timing-function
展开属性中,你均可以把这个默认的调速函数显示指定ease
关键字。除了ease外,还有四种内置的缓动曲线,你能够借助他们来改变更画的推动方式.net
从上面四个图中,咱们很直观的看出,ease-out
是ease-in
的反向版本。而这一对组合正是实现回弹效果所须要的:每当小球的运动方向相反时,咱们但愿调速函数也是相反的
。咱们但愿小球下落是加速的(ease-out)
,而弹起向上是减速的(ease-in)
:code
@keyframes bounce{ 60%,80%,to{ transform:translateY(400px); animation-timing-function:ease-out; } 70%{transform:translateY(300px);} 90%{transform:translateY(360px);} } .ball{ animation:bounce 3s ease-in; }
虽然咱们改动不大,可是已经发现回弹效果变得真实起来。不过显然这五种内置的缓动曲线
是不够用的,假如咱们这个回弹效果是用来模拟自由落体的,那么咱们须要一个更高的加速度
和ease的反向版本,又如何获得呢?
其实全部的这五种曲线都是经过(三次)贝塞尔曲线
来指定的,而CSS的调速函数都是只有一个片断的贝塞尔曲线
,每一个函数也只有两个控制锚点,CSS就提供了一个cubic-bezier()
函数,容许咱们指定自定义调速函数。他接受四个参数,分别是两个控制锚点的坐标值,
cubic-bezier(x1,y1,x2,y2)
,曲线的两个端点固定在(0,0)和(1,1)之间,前者是整个过渡的起点(时间进度0%,动画进度0%)然后者是整个过渡的终点(时间进度100%,动画进度100%)。
举例来讲,ease
等同于cubic-bezier(.25,.1,.25,1)
,所以它的反向版本就是cubic-bezier(.1,.25,1,.25)
@keyframes bounce{ 60%,80%,to{ transform:translateY(400px); animation-timing-function:ease; } 70%{ transform:translateY(300PX); } 90%{ transform:translateY(160px); } } .ball{ animation:bounce 3s cubic-bezier(.1,.25,1,.25); }
See the Pen css-animation-easing by okaychen (@okaychen) on CodePen.
咱们能够借助cubic-bezier.com的图形化工具,进行反复尝试和优化,从而进一步改写这个回弹动画.
通过以上这些知识的学习储备和练习,相信咱们已经能够作出很棒的弹跳动画了.
咱们在文章开始放了一个小球弹跳的gif图效果,那么就让咱们真真正正的动手来写一下吧!
See the Pen css-animation-easing-practice by okaychen (@okaychen) on CodePen.
假设咱们有一个文本输入框,每当它被聚焦时,都须要展现一个提示框
咱们有以下结构:
<label> Your username:<input id="username" /> <span class="callout">Only letters,numbers,usrescore(_) and hyphens (-) allowed!</span> </label>
每当用户聚焦这个文本输入框时,都会有一个半秒钟的过渡,可能咱们会完成这样的代码
input:not(:focus) + .callout{ transform:scale(0); } .callout{ transition:.5s transform; transition-origin:1.4em -.4em; }
这个过渡没有任何问题,可是咱们但愿它在结尾时能在夸张一点话,显得更加天然生动,咱们可能会把这个过渡改成一个动画,而后用上面提到的缓动曲线
@keyframes elastic-grow{ from{transform:scale(0);} 70% { transform:scale(1.1); animation-timing-function:cubic-bezier(.1,.25,1,.25); /*反向的ease*/ } } input:not(:focus) + .callout{ transform:scale(0); } input:focus + .callout{ animation:elastic-grow .5s; } .callout{ transform-origin:1.4em -.4em; }
添加了这个动画以后,确实发挥了做用。不过这里咱们其实只是须要一个过渡而已,而咱们本质上却使用了一个动画,显得有些大材小用,有一种杀鸡用牛刀的感受,咱们如何只用过渡完成这个效果呢?
这里咱们就用到了上面提及的调速函数cubic-bezier()
,在这个例子中,咱们但愿调速函数先到达110%的程度(至关于scale(1.1)
),而后在过渡回100%,咱们把控制锚点向上移,
这个自定义调速函数在垂直坐标上已经超出0~1的区间,最终又回到1,在70%的时间点到达了110%的变形程度的高峰,而后继续用剩下30%的时间回到它的最终值
整个过渡的推动,很是接近前面的动画方案,但他仅须要一行代码就能够实现整个效果
input:not(:focus) + .callout{ transform:scale(0) } .callout{ transform-origin:1.4em -.4em; transition:.5s cubic-bezier(.25,.1,.3,1.5); }
but,wait...当提示框收缩时,左下角出现的是什么?其实,当咱们把焦点从输入框切出去的时候,所触发的过渡会以scale(1)
做为起始值,并以scale(0)
做为最终值,这个过渡仍然会在350ms后到达110%的变形程度。只不过在这里,110%的变形程度的解析结果并非scale(1.1)
,而是scale(-0.1)
咱们能够定义关闭状态的css规则(假如咱们指定普通的ease调速函数)把当前的调速函数覆盖掉
input:not(:focus) + .callout{ transform:scale(0); transition-timing-function:ease; /*覆盖cubic-bezier*/ } .callout{ transform-origin:1.4em -.4em; transition:.5s cubic-bezier(.25,.1,.3,1.5); }
再试一试,发现已经关闭提示框已经恢复到咱们设置cubic-bezier()
以前的样子了,
可是其实咱们仔细观察发现另外一个问题:提示框的关闭动做明显要迟钝一些。
咱们细细想来发现,在提示框展开过程当中,当时间为50%(250ms)时,它就已经到达100%的尺寸效果了。可是在收缩过程当中,从0%~100%的变化会花费咱们为过渡所指定的素有时间(500ms),所以感受会慢上通常
而后咱们会想到同时覆盖过渡的持续时间:能够用transition-duration
这一属性,也能够用transition
这个简写属性来覆盖全部值,若是选择后者的话就不须要指定ease了,由于他原本就是transition
的初始值:
input:not(:focus) + .callout{ transform:scale(0); transition:.25s; } .callout{ transform-origin:1.4em -.4em; transition:.5s cubic-bezier(.25,.1,.3,1.5); }
See the Pen css-animation-task by okaychen (@okaychen) on CodePen.
虽然弹性过渡在不少过渡中均可以收到不错的效果,可是某些时候他产生的效果可能至关糟糕
。典型的反面案例
出如今对颜色属性
的弹性过渡中。尽管颜色发生弹性过渡可能很是有趣,但这种效果在UI场景中一般是不合适的.
为了不不当心对颜色设置了弹性过渡,能够尝试把过渡的做用范围限制在某几种特定的属性上
,transition不指定时,transition-property
就会获得它的初始值:all
,这意味着只要是过渡的属性都会参与过渡。咱们能够在transition
中设置transform
input:not(:focus){ transform:scale(0); transition:.25s transform; } .callout{ transition-origin:1.4em -.4em; transform:.5s cubic-bezier(.25,.1,.3,1.5) transform; }
参考资料