侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

详解CSS动画属性关键帧keyframes全解析

前端  /  管理员 发布于 7年前   172

大概有多久没有更新专栏文章了。半年?下半年忙到起飞,或者毫不夸张的说是发射?仅有的一点个人时间,上半年贡献给了Python,现在差不多已忘掉了七七八八(一首《凉凉》送给自己),下半年贡献给了JavaScript,终于鼓起勇气系统的开始学习JS了(换台,梁静茹《勇气》走起)。本来想一直等等等,等到webapi学完后放个大招,svg+CSS动画搭乘上JavaScript简直如虎添翼长驱直入。但是,看掘金作者群里讨论的风生水起,突然感觉自己全然是陌生人(此处应放蔡健雅?),所以,更一篇文章刷一下存在感。

这篇文章本来是写的《SVG+CSS动画》小册中的一个小节选,小册因为各种莫名的原因,搁浅了,搁浅……起航时间遥遥无期,但keyframes关键帧作为控制动画在不同时间的状态的重要元素,决定了七十二变的终极形态,所以这次更新专栏拿它下手。至于小册嘛,如果能发的话,里面再换成其他的案例就好,此为后话。

关键帧keyframes的基础概念此处可省略,下面才是满满的干货。

案例:一路向前永不停歇的圆

因为只是来解释关键帧,所以只搞了一个简易的仅水平位移的动效。因此,这篇文章得以脱离SVG单独存在仅和CSS3动画属性相关。

这是一个努力从起点滚向终点的圆圈,整个路程为800px,但我在它的必经之路的三处设置了三个驿站。现在就要通过关键帧的定义让圆圈在行进的路上进入驿站并稍作停顿。

1.先来一个最基础的

CSS部分定义一个最基础的位移动画,4s完成,线性速度case-关键帧演示1-基础 。

@keyframes  move{0%{transform:translateX(0)}100%{transform:translateX(800px)}}.c_move{animation:move 4s linear both} /*both:运动结束后停留在终点*/

这个发挥作用主要是在定义了无限循环动画时。

基础的设置自然带来毫无特色平淡无奇的基础动效。

2.延迟开始

下面,我想让圆圈在起点停留2s后再开始移动,第一反应是用动画属性中的延迟 animation-delay ,把时间定义成2s,行不行?行,但这里用个更高级的方法。我们在定义关键帧时用了大量的百分比,这里百分比值代表的是 时间节点 ,也就是说 关键帧定义的是不同时间节点的状态属性。 下面再来看一张图,这张图一定不要和上面的路径演示弄混了,这是一张动画的时间轴的图。

让圆圈在起点停留2s那是表象说法,转化成我们的动画定义语言,就是在4s动画周期内前2s是没有动画效果的。所以,动画规则我来这样定义:

@keyframes  move{0%{transform:translateX(0)}50%{transform:translateX(0px)}100%{transform:translateX(800px)}}

对照上面时间轴的分割来看,更容易理解一些,这样就得到了在起点处停留2s后,在后面的2s完成整个动画的动效。这里亦或用一种更简单的写法为 0%, 50%{transform:translateX(0)} ,属性相同的可以合并在一起,用逗号分隔。 case-关键帧演示-延迟开始

 

3.提前结束

有了延迟开始的基础,提前结束是不是已经可以类推出来了。为了区分一下,我让动画提前3s结束。照例先画出时间轴的解析。

对应关键帧的定义如下:

@keyframes  move{0%{transform:translateX(0)}25%,100%{transform:translateX(800px)}}

最终结果圆圈一定是4倍速度全力以赴加速完成旅程(毕竟要把原来4s的时间压缩到1s完成),然后怡然自得的在终点等待整个动画时间结束。 case-关键帧演示-提前结束

 

4.中途停留

那些已准备妥当的驿站,现在可以发挥作用了,我希望圆圈这样运动:整个旅程中仅在第一个驿站(移动200px后)停留1s,稍作整顿。映射到时间轴上是什么样子的呢?

这里,出现了一些看上去很奇怪的数字,需要解释一下。先来明确一点,我们分析时间轴,最终要获得是时间节点。针对我们的设计,停留1s,那运动的时间就是3s,而这3s的时间是分成两部分的,第一部分是前200px,第二部分是后600px,因为是线性匀速,所以当时间轴分成A+B+C三部分后,在A时间段跑完200px,在C时间段跑完600px,计算出A对应的时间0.75s,C对应的时间2.25s,B的时间是停留的时间1s,再换算成对应的百分比,这就是最终中间两个时间节点的计算方法。时间轴解析完成后,CSS部分的定义手到擒来:

@keyframes  move{0%{transform:translateX(0)}18.75%, 43.75%{transform:translateX(200px)} /*对应停留的1s*/100%{transform:translateX(800px)}}

case-关键帧演示-第一个驿站停留1s

 

5.像虫洞一样跳跃式前进

增加些难度,在中途任意点作停留已经不是什么问题了,停留在一个点和多个点是相同的思路,现在,我让圆圈跳跃式前进,进入第一个驿站后,停留1s,跨过第二个驿站,直接进入第三个驿站,停留1s,完成旅程。根据空间折叠原理,200和600处发生了跃迁。分析时间轴:

重点看红色的部分,那里就是跃迁的时间点,在无时间变化的情况下位移了200px。按照时间轴的分析,CSS部分理论上是这样的:

@keyframes  move{0%{transform:translateX(0)}25%,50%{transform:translateX(200px)}50%,75%{transform:translateX(600px)}100%{transform:translateX(800px)}}

效果如何呢?

完全和想象的不一样,问题出在哪里呢?就是时间的50%节点处,浏览器可不知道你真实的想法,它只会以为你定义错了,当有两个相同的50%的关键帧的不同属性值定义时,会自动忽略第一个,而以最后一个有效值为准,所以上面的定义相当于给浏览器传达的讯息是这样的:

@keyframes  move{0%{transform:translateX(0)}25%{transform:translateX(200px)}50%,75%{transform:translateX(600px)} /*在位移600px后停留1s*/100%{transform:translateX(800px)}}

这就是为什么看上去是到达第一驿站后加速跑向第三个驿站,然后停留后再完成剩下的路程的原因。现在游戏越来越有意思了,或许我们可以试试 骗过浏览器 。既然同样的时间点只允许定义一个属性值,那如果我在紧邻的旁边增加一个时间点来定义,会发生什么?

@keyframes  move{0%{transform:translateX(0)}25%,50%{transform:translateX(200px)}50.0001%,75%{transform:translateX(600px)} 100%{transform:translateX(800px)}}

看上面出现的**50.0001%**这个时间点,猜猜发生了什么?这就是上面所谓的“骗过浏览器”的方法了。在50%→50.0001%这个区间,发生了400px(200→600)的位移变化。所以就得到了下面这种效果:case-关键帧演示-跃迁

从原理上来讲,这是一种视觉欺骗,在极短的时间内在两个位置间发生位移,因为时间短到可以忽略,所以会有一种跳跃的假象。

总结

看完上面的几种代表性实例,是不是对关键帧的定义有了一个全新的认识,你可能会觉得对于“延迟开始”和“提前结束”这两种需求,是完全可以通过定义延迟时间以及动画周期的时间来达到相同的效果的,但是,对于一个无限循环的动效而言,延迟开始永远只作用一次,当动画一旦开始进入周而复始的循环后,不再支持这个属性设置。因此,如果可以的话,尽量用关键帧的定义来完成。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


  • 上一条:
    css多种方式实现等高布局的示例代码
    下一条:
    css模块化方案
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 使用 Alpine.js 排序插件对元素进行排序(0个评论)
    • 在js中使用jszip + file-saver实现批量下载OSS文件功能示例(0个评论)
    • 在vue中实现父页面按钮显示子组件中的el-dialog效果(0个评论)
    • 使用mock-server实现模拟接口对接流程步骤(0个评论)
    • vue项目打包程序实现把项目打包成一个exe可执行程序(0个评论)
    • 近期文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2017-06
    • 2017-07
    • 2017-08
    • 2017-09
    • 2017-10
    • 2017-11
    • 2018-03
    • 2018-04
    • 2018-05
    • 2018-06
    • 2018-09
    • 2018-11
    • 2018-12
    • 2019-02
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2021-04
    • 2021-05
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-11
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-09
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-02
    • 2024-03
    • 2024-04
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客