我正在参加“掘金挑战守则”。

我正在参加“掘金挑战守则”。详情请见: 掘金挑战赛来了!

华丽酷炫的动画特效总能让人感到轻松愉快,情不自禁。羡慕之余,如果也能在它华丽的外表下探寻实现逻辑,那将是成功,又向前迈进了一步。这次我们使用图像、SCSS 样式和 SVG 图像动画来为“Like”按钮设置动画,并比较差异。

图像实现

最简单和最容易理解的实现是使用图像。曾几何时,几乎所有的前端特效都需要借助图片来完成。

实现原理非常简单。一部完整的动画电影是通过不同的关键帧“拼接”出来的,每一帧都是动画每一个瞬间的“状态”。

首先声明必要的盒子模型:

 <div  class= "heart"></div>  
 复制代码

这里我们以div为例,声明伪类对象heart。

然后 heart 伪类由样式控制:

 。心 {  
 光标:指针;  
 高度:50px;  
 宽度:50px;  
 背景图像:url('https://abs.twimg.com/a/1446542199/img/t1/web_heart_animation.png');  
 背景位置:左;  
 背景重复:不重复;  
 背景大小:2900%;  
 }  
    
 .heart:悬停{  
 背景位置:对;  
 }  
    
 .is_animating {  
 动画:心爆。 8s步骤( 28) 1;  
 }  
    
 @keyframes 心跳加速{  
 从{背景位置:左;}  
 到{背景位置:右;}  
 }  
 复制代码

这里指定了背景图片位置,只显示最左边的背景元素,鼠标悬停时只显示最右边的背景元素,然后当鼠标点击div时,触发@keyframes heart-burst动画,从左向右移动,总共进行了28帧横向移动:

这样就完成了流畅的动画效果:

需要注意的是点击事件需要与JavaScript绑定,所以需要引入zepto.min.js文件

 https://cdnjs.cloudflare.com/ajax /libs/zepto /1.2.0/zepto.min.js  
 复制代码

通过 zepto.min.js 库,可以方便的操作页面节点:

 $(".heart")。 on( '点击触摸启动', function(){  
 $(这个)。 toggleClass('is_animating');  
 });  
    
 $(".heart")。 on('动画结束',函数(){  
 $(这个)。 toggleClass('is_animating');  
 });  
 复制代码

逻辑是点击事件触发动画,在动画执行过程中再次点击会移除动画效果。

此方法依赖于多帧背景图像、CSS 动画和 JavaScript 事件绑定。显然,成本有点高。同时,多帧图像平铺导致体积过大,占用系统带宽,得不偿失。

纯 SCSS(样式)实现

这种特效也可以用纯CSS样式来做,但是CSS3的原生语法太复杂了。这里我们使用 SCSS 语法。 SCSS 是 CSS3 的超集。在保证兼容性的前提下,允许变量、嵌套、混合、导入。等特性,在编写复杂的 CSS 代码时,可以简化逻辑,提高 CSS 代码的可读性。

首先让我们创建基本的盒子模型:

 <input  id= "toggle-heart" type= "checkbox"/>  
 <label  for= "toggle-heart">❤</label>  
 复制代码

在这里,like 按钮的状态由复选框和标签元素控制。

然后编写SCSS逻辑:

 $bubble-d:4.5rem; //气泡直径  
 $泡沫-r:。 5* $气泡-d; // 气泡半径  
    
 @mixin 气泡($ext){  
 变换:比例(1);  
 边框颜色:#cc8ef5;  
 边框宽度:$ext;  
 }  
    
 身体 {  
 显示:弯曲;  
 证明内容:中心;  
 边距:0;  
 高度:100vh;  
 }  
    
 [id='toggle-heart'] {  
 位置:绝对;  
 左: - 100vw;  
      
 & : 已检查 + 标签 {  
 颜色:#e2264d;  
 将改变:字体大小;  
 动画:heart 1s 三次贝塞尔曲线(. 17, . 89, . 32, 1.49);  
        
 &:之前,&:之后{  
 动画:继承;  
 动画定时功能:cubic-bezier(.21,.61,.35,1);  
 }  
        
 & :前 {  
 will-change:变换、边框宽度、边框颜色;  
 动画名称:气泡;  
 }  
 }  
 }  
    
 [for='toggle-heart'] {  
 对齐自我:中心;  
 位置:相对;  
 颜色:#aab8c2;  
 字体大小:2em;  
 光标:指针;  
      
 &:之前,&:之后{  
 位置:绝对;  
 z-index: - 1;  
 最高:50%;左:50%;  
 边界半径:50%;  
 内容: '';  
 }  
      
 & :前 {  
 box-sizing:边框框;  
 保证金:-$bubble -r;  
 边框:实心 $bubble -r #e2264d;  
 宽度:$气泡-d;高度:$气泡-d;  
 变换:比例(0);  
 }  
 }  
    
 @keyframes 心{  
 0%, 17.5% { 字体大小: 0; }  
 }  
    
 @keyframes 气泡 {  
 15% { @include 气泡($bubble -r); }  
 30%, 100% { @include 气泡(0); }  
 }  
 复制代码

这里先将checkbox按钮移出界面,然后定义气泡对象,其中bubble是指点击后会展开的紫色(#cc8ef5)气泡,直径为4.5rem,圆角:

泡泡-r:.5\泡泡-r:.5\

气泡 - r : . 5 \* 气泡-d

然后通过id选择器的toggle-heart状态判断元素的状态,触发heart和bubble动画,在一秒内动态改变heart元素和bubble元素的位置、大小和边框透明度完成动态特效。

然后添加烟花效果:

 身体 {  
 显示:弯曲;  
 证明内容:中心;  
 边距:0;  
 高度:100vh;  
 背景:线性渐变(135度,#121721,#000);  
 字体:1em verdana,无衬线;  
 }  
    
 [id='toggle-heart'] {  
 位置:绝对;  
 左: - 100vw;  
 }  
 [id='toggle-heart']:检查+标签{  
 颜色:#e2264d;  
 过滤器:无;  
 将改变:字体大小;  
 -webkit- 动画:心脏 1s 三次贝塞尔曲线(0.17、0.89、0.32、1.49);  
 动画:心脏 1s 三次贝塞尔曲线(0.17、0.89、0.32、1.49);  
 }  
 [id= 'toggle-heart' ] :checked + label :before, [id= 'toggle-heart' ] :checked + label :after {  
 -webkit- 动画:继承;  
 动画:继承;  
 -webkit- 动画计时功能:缓出;  
 动画定时功能:缓出;  
 }  
 [id='toggle-heart'] :checked + label :before {  
 will-change:变换、边框宽度、边框颜色;  
 -webkit- 动画名称:气泡;  
 动画名称:气泡;  
 }  
 [id= 'toggle-heart' ] :checked + label :after {  
 will-change:不透明度,盒子阴影;  
 -webkit- 动画名称:火花;  
 动画名称:火花;  
 }  
 [id='toggle-heart']:焦点+标签{  
 文字阴影:0 0 3px 白色,0 1px 1px 白色,0 - 1px 1px 白色,1px 0 1px 白色, - 1px 0 1px 白色;  
 }  
    
 [for='toggle-heart'] {  
 对齐自我:中心;  
 位置:相对;  
 颜色:#888;  
 字体大小:2em;  
 过滤器:灰度(1);  
 -webkit 用户选择:无;  
 -moz 用户选择:无;  
 -ms 用户选择:无;  
 用户选择:无;  
 光标:指针;  
 }  
 [for= 'toggle-heart' ] :before, [for= 'toggle-heart' ] :after {  
 位置:绝对;  
 z-index: - 1;  
 最高:50%;  
 左:50%;  
 边界半径:50%;  
 内容: '';  
 }  
 [for= 'toggle-heart' ] :before {  
 box-sizing:边框框;  
 保证金: - 2.25rem;  
 边框:实心 2.25rem #e2264d;  
 宽度:4.5rem;  
 高度:4.5rem;  
 变换:比例(0);  
 }  
 [for='toggle-heart'] :after {  
 保证金:- 0.1875rem;  
 宽度:0.375rem;  
 高度:0.375rem;  
 box-shadow: 0.32476rem - 3rem 0 - 0.1875rem #ff8080, - 0.32476rem - 2.625rem 0 - 0.1875rem #ffed80, 2.54798rem - 1.61656rem 0 - 0.1875rem #ffed80, 1.84982rem - 1.89057rem 0 - 0.1875rem # a4ff80, 2.85252rem 0.98418rem 0 - 0.1875rem #a4ff80, 2.63145rem 0.2675rem 0 - 0.1875rem #80ffc8, 1.00905rem 2.84381rem 0 - 0.1875rem #80ffc8, 1.43154rem 2.22414rem 0 - 0.1875rem #80c8ff, - 1.59425rem 2.562 rem 0 - 0.1875rem #80c8ff, - 0.84635rem 2.50595rem 0 - 0.1875rem #a480ff, - 2.99705rem 0.35095rem 0 - 0.1875rem #a480ff, - 2.48692rem 0.90073rem 0 - 0.1875rem #ff80ed, - 2.14301rem - 2.12438rem 0 - 0.1875rem #ff80ed, - 2.25479rem - 1.38275rem 0 - 0.1875rem #ff8080;  
 }  
    
 @-webkit-keyframes 心{  
 0%, 17.5% {  
 字体大小:0;  
 }  
 }  
    
 @keyframes 心{  
 0%, 17.5% {  
 字体大小:0;  
 }  
 }  
 @-webkit-keyframes 气泡 {  
 15% {  
 变换:比例(1);  
 边框颜色:#cc8ef5;  
 边框宽度:2.25rem;  
 }  
 30%, 100% {  
 变换:比例(1);  
 边框颜色:#cc8ef5;  
 边框宽度:0;  
 }  
 }  
 @keyframes 气泡 {  
 15% {  
 变换:比例(1);  
 边框颜色:#cc8ef5;  
 边框宽度:2.25rem;  
 }  
 30%, 100% {  
 变换:比例(1);  
 边框颜色:#cc8ef5;  
 边框宽度:0;  
 }  
 }  
 @-webkit-keyframes 闪闪发光{  
 0%, 20% {  
 不透明度:0;  
 }  
 25% {  
 不透明度:1;  
 box-shadow: 0.32476rem - 2.4375rem 0 0rem #ff8080, - 0.32476rem - 2.0625rem 0 0rem #ffed80, 2.1082rem - 1.26585rem 0 0rem #ffed80, 1.41004rem - 1.53985rem 0 0rem #a4ff80, 2.30412rem 0.85901rem 0 0rem #a4ff80, 2.08305rem 0.14233rem 0 0rem #80ffc8, 0.76499rem 2.33702rem 0 0rem #80ffc8, 1.18748rem 1.71734rem 0 0rem #80c8ff, - 1.35019rem 2.0552rem 0 0rem #80c8ff, - 0.60229rem 1.99916rem 0 0rem #a480ff , - 2.44865rem 0.22578rem 0 0rem #a480ff, - 1.93852rem 0.77557rem 0 0rem #ff80ed, - 1.70323rem - 1.77366rem 0 0rem #ff80ed, - 1.81501rem - 0re 1.03204m; 0re #ff  
 }  
 }  
 @keyframes 闪闪发光{  
 0%, 20% {  
 不透明度:0;  
 }  
 25% {  
 不透明度:1;  
 box-shadow: 0.32476rem - 2.4375rem 0 0rem #ff8080, - 0.32476rem - 2.0625rem 0 0rem #ffed80, 2.1082rem - 1.26585rem 0 0rem #ffed80, 1.41004rem - 1.53985rem 0 0rem #a4ff80, 2.30412rem 0.85901rem 0 0rem #a4ff80, 2.08305rem 0.14233rem 0 0rem #80ffc8, 0.76499rem 2.33702rem 0 0rem #80ffc8, 1.18748rem 1.71734rem 0 0rem #80c8ff, - 1.35019rem 2.0552rem 0 0rem #80c8ff, - 0.60229rem 1.99916rem 0 0rem #a480ff , - 2.44865rem 0.22578rem 0 0rem #a480ff, - 1.93852rem 0.77557rem 0 0rem #ff80ed, - 1.70323rem - 1.77366rem 0 0rem #ff80ed, - 1.81501rem - 0re 1.03204m; 0re #ff  
 }  
 }  
 复制代码

添加了一个新的 sparkles 对象,通过动态控制元素的颜色阴影来表达点击烟花的动态效果:

这里,为了增加效果的对比度,将背景设置为深色,并为like按钮添加亮边框:

 [id='toggle-heart']:焦点+标签{  
 文字阴影:  
 0 0 3px #fff,  
 0 1px 1px #fff, 0 - 1px 1px #fff,  
 1px 0 1px #fff,- 1px 0 1px #fff;  
 }  
 复制代码

总的来说,使用transform属性来控制元素的绝对定位、颜色、边框和盒子模型阴影来完成这个特效,带宽资源占用水平明显比图片更有优势。

SVG 实现

SVG 是矢量图形,不受像素的影响,这使得它与不同的平台或媒体更加兼容。同时,SVG对动画的支持更好,其DOM结构可以通过其特定的语法或CSS控件来定义,轻松实现动画效果。

首先还是声明盒子模型:

 <label  class= "like">  
 <input  type= "checkbox"/>  
 <div  class= "heart"/>  
 </label>  
 复制代码

然后定义样式:

 :根 {  
 --尺寸:100像素;  
 --帧数:62;  
 }  
    
 html {  
 背景颜色:#15202B;  
 最小高度:100vh;  
 显示:弯曲;  
 证明内容:中心;  
 对齐项目:居中;  
 用户选择:无;  
 }  
    
 输入 {  
 显示:无;  
 }  
    
 。喜欢 {  
 显示:块;  
 宽度:var(--size);  
 高度:var(--size);  
 光标:指针;  
 边框半径:999px;  
 溢出:可见;  
 -webkit-tap-highlight-颜色:rgba(0,0,0,0);  
 -webkit-tap-highlight- 颜色:透明;  
 }  
    
 .壁炉{  
 背景图片:url('https://assets.codepen.io/23500/Hashflag-AppleEvent.svg');  
 背景尺寸:计算(var(--size)* var(--frames))var(--size);  
 背景重复:不重复;  
 背景位置x:计算(var(--size)*(var(--frames)* - 1 + 2));  
 背景位置-y: calc(var(--size) * 0.02);  
 宽度:var(--size);  
 高度:var(--size);  
 }  
    
 输入:检查 + .hearth {  
 动画:像 1s 步(计算(var(--frames)- 3));  
 动画填充模式:转发;  
 }  
    
 @keyframes 像 {  
 0% {  
 背景位置-x:0;  
 }  
 100% {  
 背景位置-x: calc( var(--size) * ( var(--frames) * - 1 + 3));  
 }  
 }  
    
 @媒体(悬停:悬停){  
 .like :hover {  
 背景颜色:#E1255E15;  
 .壁炉{  
 背景位置-x: calc( var(--size) * ( var(--frames) * - 1 + 1));  
 }  
 }  
 }  
 复制代码

和普通图片完全一样。 background-image用于控制背景SVG图片的顺序,进行背景横坐标的横向移动,但帧数增加到62帧:

这里可以看到像水平动画一样的@keyframes可以通过input:checked状态触发,不需要单独编写JavaScript逻辑。

结语

三种动画特效实现方式各有千秋,但从可维护性和成本控制的角度来看,SCSS显然是最优方案。

版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议。转载请附上原文出处链接和本声明。

这篇文章的链接: https://homecpp.art/4406/7155/2130

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明

本文链接:https://www.qanswer.top/20704/32180700

posted @ 2022-09-07 00:33  哈哈哈来了啊啊啊  阅读(21)  评论(0编辑  收藏  举报