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

写在前面

上一篇中我们熟悉五种内置的缓动曲线和(三次)贝塞尔曲线,并且基于此完成了缓动效果.

但是如果我们想要实现逐帧动画,基于贝塞尔曲线的调速函数就显得有些无能为力了,因为我们并不需要帧与帧之间的过渡状态,就像上篇中所看到的,所有基于贝塞尔曲线的调速函数都会在关键帧之间进行插值运算,从而产生平滑的过渡效果。

这个特性显然很棒,平滑的效果确实是我们使用css过渡和动画所追求的。

但是在逐帧动画的场景下,这种平滑的特性恰恰毁掉了我们想要实现的逐帧动画的效果.

逐帧动画

我们经常会看到一段卡通影片、一个复杂进度的提示框、一个小loading, 我们不会单纯的选择一张GIF动画胜任,因为它的局限性和短板表现的很明显.

  • GIF图片所能使用的颜色数量被限制在256色
  • GIF不具有Alpha透明的特性,
  • GIF动画一旦生成,参数就固定在文件内部,只能通过图像处理软件去重新生成. 在某些场景下,基于图片的逐帧动画成了不错的选择。

steps()调速函数

写在前面中提到,我们不能基于贝塞尔曲线的调速函数完成我们所需要的逐帧动画,那么采用什么调速函数呢?

对,答案就是steps()调速函数,与贝塞尔曲线迥然不同的是,steps()会根据你指定的步进数量,把动画分为很多帧,而且整个动画会在帧与帧之间硬切,不会像贝塞尔曲线那样做插值处理。

通过上图我们可以很明显看出steps(8)、linear和ease的区别.

其实这种硬切效果是我们极力避免的,因此我们也很少听到关于steps()的讨论。在CSS调速函数的世界里,基于贝塞尔曲线的调速函数就像是被人追捧的白天鹅,而steps()则是旁人唯恐不及的丑小鸭。

其实无所谓好与不好,更多的是适合与不适合,我们都崇拜的贝塞尔曲线在像小"loading"这样的逐帧动画中失败了,而steps()却展示出我们想要的效果.

这个想法最初是Simurai在他的博客中推出http://simurai.com/blog/2012/12/03/step-animation,他使用steps()实现拼合图片的动画效果.让人印象深刻

codepen中查看效果

ch单位 - css值与单位第三版

有时候,我们希望一段为本字符逐个显示,模拟出一种打字的效果。这种效果在技术类网站中尤为常见,用等宽字体可以营造出一种终端命令行的感觉.

<h1>CSS is amazing!</h1>
@keyframes typing{
    from{width:0}
}
h1{
    width:7.7em;
    white-space:nowrap;
    overflow:hidden;
    animation:typing 8s;
}

我们想要模拟出一种打字效果,但是

  • 整个动画是平滑连贯的,而不是逐字显示
  • 目前我们已经使用em指定宽度是7.7,虽然他比像素单位好一些,但是仍然不够理想,这个宽度为什么是7.7em.

我们很自然的想到了使用steps()来修复第一个问题,但是不幸的是,我们所需要的步进数量是由字符的数量来决定的

CSS值与单位(第三版)规范引入了一个新的单位,表示"0"字形的宽度。大多数场景下,我们不必关心"0"字形的宽度到底有多宽,因为在等宽字体中,"0"字形的宽度和其他所有字形的宽度是一样的。因此,我们如果使用ch单位来表示h1的宽度,那取值实际上就是字符的数量:在上面的例子中就是15

@keyframes typing{
    from{ width:0 }
}
@keyframes caret{
    50%{ border-color:transparent }
}
h1{
    width:15ch;
    overflow:hidden;
    white-space:nowrap;
    border-right:0.5em solid;
    animation:typing 6s steps(15),caret 1s steps(1) infinite;
}

但是我们还是有些疑问:

  • 这样的代码是不易维护的,当更新标题的时候,我们总是需要根据字符的数量来指定不同的宽度样式和steps()函数,这时候正是JavaScript的用武之地 function $$(selector,context){ context = context||document; var elements = context.querySelector(selector); return Array.prototype.slice.call(elements); } $$('h1').forEach(function(h1){ var len = h1.textContent.length,s = h1.style; s.width = len + 'ch'; s.animationTimingFunction = "steps(" + len + "),steps(1)" })
  • 如果浏览器不支持ch单位,我们该怎么办?这时候就需要实现样式的回退,如果不希望字体出现异常,会选择补一行em作为单位的回退样式

写在最后

这一篇主要基于steps()函数和ch单位,详细的比较了steps()调速函数和基于贝塞尔曲线调速函数的区别,虽然steps()调速函数像是旁人唯恐不及的丑小鸭,但是它亦有其独特的魅力。

参考资料

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏前端知识分享

第72天:jQuery实现下拉菜单

1、块元素居中:给块元素本身设置:margin:0 auto;,块元素必须设置宽度

592
来自专栏前端那些事

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

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

24310
来自专栏py+selenium

python爬虫常用正则表达式组合匹配

正则表达式在线测试工具:http://tool.oschina.net/regex/?optionGlobl=global

711
来自专栏smy

多行图片hover加边框兼容IE7+

问题: 遇到多行多列排列的图片时,hover上去加边框会把下面的图片挤到别处 =========================================...

3316
来自专栏IMWeb前端团队

移动端重构实战系列1——基础知识

距离上个移动端重构系列已是两年了(不得不感叹时间是把杀猪刀)。这次将会带来实战系列,将欠下两年的债现在还上,给七年的重构赋予一次新生。 既然是新的开始,先简单说...

1700
来自专栏菜鸟计划

CSS基础语法(二) CSS的9种选择器

样式表的选择器 1.类选择器 根据HTML标签的class属性选择样式应用的属性  .类值{ … } 2.ID选择器 根据HTML标签的ID属性选择样式应用的元...

3323
来自专栏WD学习记录

牛客网 正则表达式匹配

请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是...

712
来自专栏一个小程序员的成长笔记

CSS3弹性盒布局

使用自适应的窗口弹性盒布局 可以使div总宽度等于浏览器宽度,而且可以随着浏览器的改变而改变。 1 <!DOCTYPE html> 2 <html la...

4277
来自专栏WOLFRAM

把图像结合到画图当中

1253
来自专栏知道一点点

sass入门学习篇(一)

Sass 是对 CSS 的扩展,让 CSS 语言更强大、优雅。 它允许你使用变量、嵌套规则、 mixins、导入等众多功能, 并且完全兼容 CSS 语法。 Sa...

733

扫码关注云+社区