你可能不知道的Animation动画技巧与细节
引言
在web应用中,前端同学在实现动画效果时往往常用的几种方案:
- css3 transition / animation - 实现过渡动画
- setInterval / setTimeout - 通过设置一个间隔时间来不断的改变图像的位置
- requestAnimationFrame - 通过一个回调函数来改变图像位置,由系统来决定这个回调函数的执行时机,比定时修改的性能更好,不存在失帧现象
在大多数需求中,css3的 transition / animation 都能满足我们的需求,并且相对于js实现,可以大大提升我们的开发效率,降低开发成本。
本篇文章将着重对 animation 的使用做个总结,如果你的工作中动画需求较多,相信本篇文章能够让你有所收获:
- Animation 常用动画属性
- Animation 实现不间断播报
- Animation 实现回弹效果
- Animation 实现直播点赞效果 ️
- Animation 与 Svg 又会擦出怎样的火花呢?
- Loading 组件
- 进度条组件
- Animation steps() 运用
- 实现打字效果
- 绘制帧动画
Animation 常用动画属性 参考资料

介绍完 animation 常用属性,为了将这些属性更好地理解与运用,下面将手把手实现一些DEMO具体讲述
Animation 实现不间断播报 Online Code

通过修改内容在父元素中的y轴的位置来实现广播效果
@keyframes scroll {
0%{
transform: translate(0, 0);
}
100%{
transform: translate(0, -$height);
}
}
.ul {
animation-name: scroll;
animation-duration: 5s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
此处为了保存广播滚动效果的连贯性,防止滚动到最后一帧时没有内容,
需要多添加一条重复数据进行填充
<div class="ul">
<div class="li">小刘同学加入了凹凸实验室</div>
<div class="li">小邓同学加入了凹凸实验室</div>
<div class="li">小李同学加入了凹凸实验室</div>
<div class="li">小王同学加入了凹凸实验室</div>
<div class="li">小刘同学加入了凹凸实验室</div>
</div>
Animation 实现回弹效果 Online Code
通过将过渡动画拆分为多个阶段,每个阶段的top属性停留在不同的位置来实现

@keyframes animation {
0% {
top: -100%;
opacity: 0;
}
25% {
top: 60%;
opacity: 1;
}
50% {
top: 48%;
opacity: 1;
}
75% {
top: 52%;
opacity: 1;
}
100% {
top: 50%;
opacity: 1;
}
}
为了让过渡效果更自然,这里通过
cubic-bezier()函数定义一个贝塞尔曲线来控制动画播放速度过渡动画执行完后,为了将让元素应用动画最后一帧的属性值,我们需要使用
animation-fill-mode: forwards
.popup {
animation-name: animate;
animation-duration: 0.5s;
animation-timing-function: cubic-bezier(0.21, 0.85, 1, 1);
animation-iteration-count: 1;
animation-fill-mode: forwards;
}
Animation 实现点赞效果 Online Code

相信大多数同学都知道点赞效果,本文章会实现一个简易版的点赞效果,主要讲述一下实现思路:
1.为了让气泡可以向上偏移,我们需要先实现一个y轴方向上移动的 @keyframes 动画
@keyframes animation-y {
0%{
transform: translate(-50%, 100px) scale(0);
}
50%{
transform: translate(-50%, -100px) scale(1.5);
}
100%{
transform: translate(-50%, -300px) scale(1.5);
}
}
2.为了让气泡向上偏移时显得不太单调,我们可以再实现一个x轴方向上移动的 @keyframes 动画
@keyframes animation-x {
0%{
margin-left: 0px;
}
25%{
margin-left: 25px;
}
75%{
margin-left: -25px;
}
100%{
margin-left: 0px;
}
}
这里我理解:
- 虽然是
修改 margin来改变x轴偏移距离,但实际上与修改 transform没有太大的性能差异 - 因为通过
@keyframes animation-y中的transform已经新建了一个渲染层 ( PaintLayers ) animation属性 可以让该渲染层提升至合成层(Compositing Layers)拥有单独的图形层 ( GraphicsLayer ),即开启了硬件加速 ,不会影响其他渲染层的paint、layout- 如下图所示:

如笔者这里理解有误,还请读者大佬指出,感激不尽~
3.给气泡应用上我们所实现的两个 @keyframes 动画
.bubble {
animation: animation-x 3s -2s linear infinite,animation-y 4s 0s linear 1;
}
4.在点赞事件中,通过 js 操作动态添加/移除气泡元素
function like() {
const likeDom = document.createElement('div');
likeDom.className = 'bubble';
document.body.appendChild(likeDom);
setTimeout( () => {
document.body.removeChild(likeDom);
}, 4000)
}
Animation 与 Svg 绘制 loading/进度条 组件 Online Code

1.首先,我们使用 svg 绘制一个圆周长为2 * 25 * PI = 157 的圆
<svg with='200' height='200' viewBox="0 0 100 100" >
<circle cx="50" cy="50" r="25" fill="transparent" stroke-width="4" stroke="#0079f5" ></circie>
</svg>

2.将实线圆绘制成虚线圆,这里需要用 stoke-dasharray:50, 50 (可简写为50) 属性来绘制虚线, stoke-dasharray 参考资料
- 它的值是一个数列,数与数之间用逗号或者空白隔开,指定
短划线(50px)和缺口(50px)的长度。 - 由于
50(短划线) + 50(缺口) + 50(段划线) = 150, 150 < 157,无法绘制出完整的圆,所以会导致右边存在缺口(7px)
<svg with='200' height='200' viewBox="0 0 100 100" >
<circle cx="50" cy="50" r="25" fill="transparent" stroke-width="4" stroke-dasharray="50" stroke="#0079f5" ></circie>
</svg>

3.stroke-dashoffset 属性可以使圆的短划线和缺口产生偏移,添加 @keyframes 动画后能够实现从无到有的效果,stoke-dashoffset参考资料
- 设置
stroke-dasharray="157 157",指定短划线(157px)和缺口(157px)的长度。 - 添加 @keyframes 动画
修改stroke-dashoffset值, 值为正数时逆时针偏移,, 值为负数时,顺时针偏移
@keyframes loading {
0%{
stroke-dashoffset: 0;
}
100%{
stroke-dashoffset: -157;
}
}
circle{
animation: loading 1s 0s ease-out infinite;
}

4.修改短划线和缺口值
- 为了让 loading 组件线条可见,我们需要一个
50px的短划线,设置stroke-dasharray="50" - 为了让短划线发生偏移后可以完全消失,
缺口需要大于或等于圆周长157,设置stroke-dasharray="50 157" - 添加 @keyframes 动画,为了让
动画结束时仍处理动画开始位置,需要修改 stroke-dashoffset:-207(短划线+缺口长度) - 进度条也是类似原理,帮助理解
stroke-dashoffset属性,具体实现请查看示例
@keyframes loading {
0%{
stroke-dashoffset: 0;
}
100%{
stroke-dashoffset: -207;
}
}
circle{
animation: loading 1s 0s ease-out infinite;
}
Animation steps()运用
steps() 是 animation-timing-function 的属性值
animation-timing-function : steps(number[, end | start])
- steps 函数指定了一个阶跃函数,它接受
两个参数 第一个参数接受一个整数值,表示两个关键帧之间分几步完成第二个参数有两个值 start or end。默认值为 end- step-start 等同于 step(1, start)。step-end 等同于 step(1, end)
steps 适用于关键帧动画,第一个参数将两个关键帧细分为N帧,第二个参数决定从一帧到另一帧的中间间隔是用开始帧还是结束帧来进行填充。
看下图可以发现:
steps(N, start)将动画分为N段,动画在每一段的起点发生阶跃(即图中的空心圆 → 实心圆),动画结束时停留在了第N帧steps(N, end)将动画分为N段,动画在每一段的终点发生阶跃(即图中的空心圆 → 实心圆),动画结束时第N帧已经被跳过(即图中的空心圆 → 实心圆),停留在了N+1帧。

实践出真知!
Animation 实现打字效果 Online Code

- 此处用英文字母(I'm an O2man.)举例,一共有
13个字符。[经测试,多数中文字体每个字符宽高都相等] steps(13)可以将 @keyframes 动画分为13阶段运行,且每一阶段运行距离相等。
效果如下:

@keyframes animate-x {
0%{
width: 0;
}
}
p {
width: 125px;
overflow: hidden;
border-right: 1px solid transparent;
animation: animate-x 3s 0s steps(13) 1 forwards;
}
- 可以发现仅仅这样还不够,动画运行过程中出现了字符被截断的情况,为了保证每个阶段运行后能准确无误地显示当前所处阶段的字符,我们还需要保证
每个字符的width与动画每一阶段运行的距离相等 - 设置
Monaco字体属性,用以保证每个字符的 width 相同,具体像素受fontSize属性影响,示例中的字体宽度约为 9.6px,9.6px * 13(段数) = 124.8px (125px),所以当我们设置容器宽度为 125px,即可的达成目的:每个字符的 width 与动画每一阶段运行的距离相等(约为 9.6px )。
p {
font-family: Monaco;
width: 125px ;
font-size: 16px;
overflow: hidden;
border-right: 1px solid transparent;
animation: animate-x 3s 0s steps(13) 1 forwards,cursor-x 0.4s 0s linear infinite;
}
Animation 实现帧动画 Online Code

- 这里我们拿到了一张
47帧的雪碧图(css spirit),设置背景图
.main {
width: 260px;
height: 200px;
background: url(url) no-repeat;
background-size: 100%;
background-position: 0 0;
}
- 添加 @keyframes
修改 background-position,让背景图移动
@keyframes animate {
0% {
background-position: 0 0;
}
100% {
background-position: 0 100%;
}
}
.main{
width: 260px;
height: 200px;
background: url(url) no-repeat;
background-size: 100%;
background-position: 0 0;
animation: animate 2s 1s steps(47) infinite alternate;
}
- 同时, css 还提供了
animation-play-state用于控制动画是否暂停
input:checked+.main{
animation-play-state: paused;
}
文章篇幅较长,感谢大家的阅读,希望各位看客能够有所收获~ ~ ~
如果这篇文章对你有帮助,欢迎关注我的博客
参考资料
CSS 参考手册
SVG学习之stroke-dasharray 和 stroke-dashoffset 详解
理解CSS3 Animation中的steps()
【译】css动画里的steps()用法详解
CSS Will Change
你可能不知道的Animation动画技巧与细节的更多相关文章
- 你所不知道的 CSS 动画技巧与细节
怕标题起的有点大,下述技巧如果你已经掌握了看看就好,欢迎斧正,本文希望通过介绍一些 CSS 不太常用的技巧,辅以一些实践,让读者可以更加深入的理解掌握 CSS 动画. 废话少说,直接进入正题,本文提到 ...
- 你所不知道的 CSS 滤镜技巧与细节
承接上一篇你所不知道的 CSS 动画技巧与细节,本文主要介绍 CSS 滤镜的不常用用法,希望能给读者带来一些干货! OK,下面直接进入正文.本文所描述的滤镜,指的是 CSS3 出来后的滤镜,不是 IE ...
- 你所不知道的 CSS 阴影技巧与细节
关于 CSS 阴影,之前已经有写过一篇,box-shadow 与 filter:drop-shadow 详解及奇技淫巧,介绍了一些关于 box-shadow 的用法. 最近一个新的项目,CSS-Ins ...
- 你所不知道的 CSS 阴影技巧与细节 滚动视差?CSS 不在话下 神奇的选择器 :focus-within 当角色转换为面试官之后 NPOI 教程 - 3.2 打印相关设置 前端XSS相关整理 委托入门案例
你所不知道的 CSS 阴影技巧与细节 关于 CSS 阴影,之前已经有写过一篇,box-shadow 与 filter:drop-shadow 详解及奇技淫巧,介绍了一些关于 box-shadow ...
- 【CSS】346- 你所不知道的 CSS 阴影技巧与细节
偷懒了1个多礼拜,在工作饱和的情况下,怎么坚持学习?今天的分享来自@Coco国服第一切图仔,我们聊聊CSS属性box-shadow- 关于 CSS 阴影,之前已经有写过一篇,box-shadow 与 ...
- 你所不知道的 CSS 负值技巧与细节
写本文的起因是,一天在群里有同学说误打误撞下,使用负的 outline-offset 实现了加号.嗯?好奇的我马上也动手尝试了下,到底是如何使用负的 outline-offset 实现加号呢? 使用负 ...
- css3 animation动画技巧
一,css3 animation动画前言 随着现在浏览器对css3的兼容性越来越好,使用css3动画来制作动画的例子也越来越广泛,也随着而来带来了许多的问题值得我们能思考.css3动画如何让物体运动更 ...
- 【转载】14个你可能不知道的 JavaScript 调试技巧
了解你的工具可以极大的帮助你完成任务.尽管 JavaScript 的调试非常麻烦,但在掌握了技巧 (tricks) 的情况下,你依然可以用尽量少的的时间解决这些错误 (errors) 和问题 (bug ...
- 14 个你可能不知道的 JavaScript 调试技巧
了解你的工具可以极大的帮助你完成任务.尽管 JavaScript 的调试非常麻烦,但在掌握了技巧 (tricks) 的情况下,你依然可以用尽量少的的时间解决这些错误 (errors) 和问题 (bug ...
随机推荐
- 【LeetCode】 204. Count Primes 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 素数筛法 参考资料 日期 [LeetCode] 题目 ...
- Java基础(八)——IO流1_字节流、字符流
一.概述 1.介绍 I/O是 Input/Output 的缩写,IO流用来处理设备之间的数据传输,如读/写文件,网络通讯等.Java对数据的操作是通过流的方式进行.java.io 包下提供了各种&qu ...
- CS5263|DP转HDMI转换器芯片|CS5263芯片说明
CS5263是一款高性能DP1.4到HDMI2.0b功能芯片,设计用于将DP1.4源连接到HDMI2.0b接收器.CS5263集成了DP1.4兼容接收机和HDMI2.0b兼容接收机发射器.DP接口包括 ...
- Java基础寒假作业-简易计算器
需求: 使用Java编写计算器的控制台程序,完成简单的加减乘除运算.实现以下功能: 1.运算选择 请用户选择一个算法(1.加法 2.减法 3.乘法 4.除法 5.关闭计算器) 2.计算 a)加法:实现 ...
- 【MySQL作业】DDL 和 DML——美和易思使用 DML 新增和更新表数据应用习题
点击打开所使用到的数据库>>> 1.添加 easyShopping 客户数据. insert into customer values('abc111','111',' 刘一鸣 ', ...
- Oracle导出导入dmp文件(exp.imp命令行)
1.说明 使用Oracle命令行导出导入dmp文件, 从而在两个数据库之间快速转移数据, 也可以用来作为数据库的备份, 将来可以快速恢复数据. 命令:导出exp.导入imp 步骤: 使用Oracle的 ...
- RSA非对称加密算法实现:Python
RSA是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.当时他们三人都在麻省理工学院工作.RSA ...
- Fences桌面图标分类
1.简介 Fences也称为栅栏桌面, 可以用来分类和组织桌面上的图标. Fences可以将不同的图标放到不同的容器当中, 还可以自由的设置这个容器,比如移动和拉伸等等. 这样图标分类后,桌面就整洁多 ...
- SpringBoot 之 多环境切换
方式一:分开多个配置文件 # /src/main/resources/application.yaml server: port: 8080 spring: profiles: active: dev ...
- 初识python 之 爬虫:爬取某网站的壁纸图片
用到的主要知识点:requests.get 获取网页HTMLetree.HTML 使用lxml解析器解析网页xpath 使用xpath获取网页标签信息.图片地址request.urlretrieve ...