关于css3:你可能不知道的Animation动画技巧与细节

2次阅读

共计 6148 个字符,预计需要花费 16 分钟才能阅读完成。

作者:阿文

原文:https://aotu.io/notes/2020/10…

本篇将着重对 animation 的应用做个总结。

引言

在 web 利用中,前端同学在实现动画成果时往往罕用的几种计划:

  1. css3 transition / animation – 实现过渡动画
  2. setInterval / setTimeout – 通过设置一个间隔时间来一直的扭转图像的地位
  3. requestAnimationFrame – 通过一个回调函数来扭转图像地位,由零碎来决定这个回调函数的执行机会,比定时批改的性能更好,不存在失帧景象

在大多数需要中,css3 的 transition / animation 都能满足咱们的需要,并且绝对于 js 实现,能够大大晋升咱们的开发效率,升高开发成本。

本篇文章将着重对 animation 的应用做个总结,如果你的工作中动画需要较多,置信本篇文章可能让你有所播种:

  • Animation 罕用动画属性
  • Animation 实现不间断播报
  • Animation 实现回弹成果
  • Animation 实现直播点赞成果 ❤️
  • Animation 与 Svg 又会擦出怎么的火花呢?????

    1. Loading 组件
    2. 进度条组件
  • Animation steps() 使用 ⏰

    1. 实现打字成果
    2. 绘制帧动画

Animation 罕用动画属性

介绍完 animation 罕用属性,为了将这些属性更好地了解与使用,上面将手把手实现一些 DEMO 具体讲述

Animation 实现不间断播报

实现不间断播报 DEMO

通过批改内容在父元素中的 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;  
 /\* animation: scroll 5s linear 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 实现回弹成果

通过将过渡动画拆分为多个阶段,每个阶段的 top 属性停留在不同的地位来实现

实现回弹成果 DEMO


/\* 规定动画,扭转 top,opacity */  
@keyframes animate {  
 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: animate 0.5s cubic-bezier(0.21, 0.85, 1, 1) 1 forwards; 动画属性简写 */  
}  

Animation 实现点赞成果 Online Code

实现点赞成果 DEMO

置信大多数同学都晓得点赞成果,本文章会实现一个简易版的点赞成果,次要讲述一下实现思路:

  1. 为了让气泡能够向上偏移,咱们须要先实现一个 y 轴方向上挪动的 @keyframes 动画

/\* 规定动画,扭转 y 轴偏移间隔 */  
@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);  
 }  
}  
  1. 为了让气泡向上偏移时显得不太枯燥,咱们能够再实现一个 x 轴方向上挪动的 @keyframes 动画

/\* 规定动画,扭转 x 轴偏移间隔 */  
@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
  • 对于 合成层 (Compositing Layers) 相干常识不是很理解的同学,能够浏览一下这篇文章从浏览器渲染层面解析 css3 动效优化原理
  • 如下图所示:

如笔者这里了解有误,还请读者大佬指出,感激不尽~

  1. 给气泡利用上咱们所实现的两个 @keyframes 动画
.bubble {  
 animation: animation-x 3s -2s linear infinite,animation-y 4s 0s linear 1;  
/\*  给 bubble 开启了硬件加速 */  
}  
  1. 在点赞事件中,通过 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

Animation 与 Svg 绘制 loading/ 进度条 组件 ???? DEMO

  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>  

  1. 将实线圆绘制成虚线圆,这里须要用 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>  

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

  1. 批改短划线和缺口值
  • 为了让 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 实现打字成果

Animation 实现打字成果 DEMO

  • 此处用英文字母 (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 {  
 /\* 设置 Monaco 字体属性,字体大小为 16px,用以保障每个字符的 width 雷同,width 约为 9.6p */  
 font-family: Monaco;  
 /\* 9.6px * 13 = 124.8px (125px) */  
 width: 125px ;  
 font-size: 16px;  
 overflow: hidden;  
 border-right: 1px solid transparent;  
 /\* 同时利用动画 animate-x、cursor-x */  
 animation: animate-x 3s 0s steps(13) 1 forwards,cursor-x 0.4s 0s linear infinite;  
}  

Animation 实现帧动画 ⏰

Animation 实现帧动画 ⏰ DEMO

  • 这里咱们拿到了一张 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;}  

文章篇幅较长,感激大家的浏览,心愿各位看客可能有所播种~ ~ ~


参考资料

Animation 罕用动画属性
CSS 参考手册
steps() 参考资料
SVG 学习之 stroke-dasharray 和 stroke-dashoffset 详解
了解 CSS3 Animation 中的 steps()
【译】css 动画里的 steps()用法详解
CSS Will Change

相干文章

  1. 104 道 CSS 面试题,助你查漏补缺
  2. 20 个让你效率更高的 CSS 代码技巧

最初,欢送关注我的公众号:前端开发博客,回复 加群,一起学习提高。

正文完
 0