难题

给过渡和动画加上缓动效果是一种常见的手法(比如具有回弹效果的过渡过程)是一种流行的表现手法,可以让界面显得更加生动和真实:在现实世界中,物体A点到B点往往也是不完全匀速的

以纯技术的角度来看,回弹效果是指当一个过渡达到最终值时,往回到一点,然后再次回到最终值,如此往复一次或者多次,并逐渐收敛,最终稳定在最终值。有相当的多JavaScript类库可以创建动画,且内置回弹效果等其他缓动效果。但是眼下,我们其实已经不需要借助脚本来实现过渡和动画了。不过,在CSS中实现回弹效果的最佳方式是什么呢?

弹跳动画

我们的第一感觉可能就是使用css动画,并且设置如下关键帧:

@keyframes bounce{
60%,80%,to{transform:translateY(350px);}
70%{transform:translateY(250px);}
90%{transform:translateY(300px);}
}

相信我们都做过这样的事,但是我们跑一遍这个动画,会发现它显示的及其不真实,主要原因在于,每当这个小球方向改变时,她得移动过程都是持续加速的,这看起来很不自然。原因其实就是因为它的调速函数在关键帧的衔接都是一样的

所有的过渡和动画之间都是跟一条曲线有关的,这条曲线指定了动画过程在整段时间中是如何推进的

如果不指定调速函数,就是得到一个默认值。但是这个默认值并不是我们想象中的匀速效果,而是:

注意,当时间进行到一半时,这个过渡已经推进到80%.

说到调速函数,我们很自然联系到了css内置的缓动曲线和贝塞尔曲线。

不论是在animation/transition简写属性中,还是在animation-timing-function/transition-timing-function展开属性中,你都可以把这个默认的调速函数显示指定ease关键字。除了ease外,还有四种内置的缓动曲线,你可以借助他们来改变动画的推进方式

从上面四个图中,我们很直观的看出,ease-outease-in的反向版本。而这一对组合正是实现回弹效果所需要的:每当小球的运动方向相反时,我们希望调速函数也是相反的。我们希望小球下落是加速的(ease-out),而弹起向上是减速的(ease-in):

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

codepen中查看效果

See the Pen css-animation-easing by okaychen (@okaychen) on CodePen.

我们可以借助cubic-bezier.com的图形化工具,进行反复尝试和优化,从而进一步改写这个回弹动画.

最后

经过以上这些知识的学习储备和练习,相信我们已经可以做出很棒的弹跳动画了.

我们在文章开始放了一个小球弹跳的gif图效果,那么就让我们真真正正的动手来写一下吧!

codepen中查看效果

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

codepen中查看效果

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

参考资料

过渡与动画 - 缓动效果&基于贝塞尔曲线的调速函数的更多相关文章

  1. window.requestAnimationFrame与Tween.js配合使用实现动画缓动效果

    window.requestAnimationFrame 概述 window.requestAnimationFrame()这个方法是用来在页面重绘之前,通知浏览器调用一个指定的函数,以满足开发者操作 ...

  2. 过渡与动画 - steps调速函数&CSS值与单位之ch

    写在前面 上一篇中我们熟悉五种内置的缓动曲线和(三次)贝塞尔曲线,并且基于此完成了缓动效果. 但是如果我们想要实现逐帧动画,基于贝塞尔曲线的调速函数就显得有些无能为力了,因为我们并不需要帧与帧之间的过 ...

  3. 过渡与动画 - 逐帧动画&steps调速函数

    写在前面 上一篇中我们熟悉五种内置的缓动曲线和(三次)贝塞尔曲线,并且基于此完成了缓动效果. 但是如果我们想要实现逐帧动画,基于贝塞尔曲线的调速函数就显得有些无能为力了,因为我们并不需要帧与帧之间的过 ...

  4. Adobe Edge Animate –弹性的方块-使用tweenmax缓动效果

    Adobe Edge Animate –弹性的方块-使用tweenmax缓动效果 版权声明: 本文版权属于 北京联友天下科技发展有限公司. 转载的时候请注明版权和原文地址. 此前有Edge爱好者提出一 ...

  5. 【WPF学习】第五十一章 动画缓动

    线性动画的一个缺点是,它通常让人觉得很机械且不能够自然.相比而言,高级的用户界面具有模拟真实世界系统的动画效果.例如,可能使用具有触觉的下压按钮,当单击时按钮快速弹回,但是当没有进行操作时它们会慢慢地 ...

  6. javascript的缓动效果

    这部分对原先的缓动函数进行抽象化,并结合缓动公式进行强化.成品的效果非常惊人逆天.走过路过不要错过. 好了,打诨到此为止.普通的加速减速是难以让人满意的,为了实现弹簧等让人眼花缭乱的效果必须动用缓动公 ...

  7. 重新想象 Windows 8 Store Apps (19) - 动画: 线性动画, 关键帧动画, 缓动动画

    原文:重新想象 Windows 8 Store Apps (19) - 动画: 线性动画, 关键帧动画, 缓动动画 [源码下载] 重新想象 Windows 8 Store Apps (19) - 动画 ...

  8. 软件项目技术点(1)——Tween算法及缓动效果

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 Tween算法及缓动效果 软件里在切换步序时需要有过渡动画效果,从当前位置的画面缓动到目标位置的画面.动画效果可重新查看文章系列第一篇 ...

  9. 背水一战 Windows 10 (15) - 动画: 缓动动画

    [源码下载] 背水一战 Windows 10 (15) - 动画: 缓动动画 作者:webabcd 介绍背水一战 Windows 10 之 动画 缓动动画 - easing 示例演示缓动(easing ...

随机推荐

  1. Wim镜像编辑

    1.挂载install.wim文件为本地的一个文件夹 dism /mount-wim  /wimfile:D:\install.wim /index:1 /mountdir:D:\Win 注:1> ...

  2. JVM内核优化

    1.垃圾回收器 JVM垃圾回收器有串行和并行两种. 1.1 Serial收集器(串行,单线程),现在使用较少 Serial一般收集新生代 SerialOld一般收集老年代(采用标记压缩算法) 1.2 ...

  3. [20180118]tstats的问题.txt

    [20180118]tstats的问题.txt --//关于使用tstats收集处理统计信息,可以看链接http://blog.itpub.net/267265/viewspace-1987839/ ...

  4. EF Core扩展工具记录

    Microsoft.EntityFrameworkCore.AutoHistory Microsoft.EntityFrameworkCore 的一个插件,支持自动记录数据更改历史记录. GitHub ...

  5. C#语言————第二章 C#语言快速热身

    第二章    C#语言快速热身 ***********一.选择结构**************** 1:if选择结构与java的if选择结构语法完全相同 2:switch选择结构 ①:常量表达式的值可 ...

  6. 在 Android 手机上运行 Python 程序

  7. java针对不同方法的分页

    一.常见的分页实现方式 ①使用List接口中的subList(int startIndex,int endIndex)方法实现分页 ②直接使用数据库SQL语句实现分页 ③使用hibernate等框架实 ...

  8. The Art of Unit Testing With Examples in .NET

    The Art of Unit Testing With Examples in .NET

  9. asp.net core 中使用StyleCop.StyleCopAnalyzers

    1.nuget中安装 StyleCop.Analyzers 当前版本1.1.0-beta004 2.在项目根目录新增 stylecop.json文件 { "settings": { ...

  10. React学习笔记_01

    使用Facebook的create-react-app快速构建React开发环境 前言: create-react-app:来自Facebook官方的零配置命令行工具 create-react-app ...