irpas技术客

HTML5+CSS3高级动画的应用实践_flying meng的菜鸟居

网络 3023

我们大概都知道css可以用来作平面旋转、扭曲、放大缩小、平移。。。并且用起来几乎都得心应手。 但目前来说,3D效果的“高级”动画似乎更受欢迎一些,而且我们也确实需要。


这不,前两天笔者就在项目中给“翻转动画”增加了一个3D效果,看起来贼爽:

这个动画实现所用到的3D盒子模型是现在3D模型中最常用的一个 —— 不过我们先拿其中两个面分析:

首先,要实现这个功能,我们从外往里看:把文字所在部分看作一个盒子的话,前后两个横线并不属于这个盒子才对,那么,很自然就想到了—— ::after 和 ::before 伪元素;其次,两个文字分别在两个div上,那么就需要有一个可以附带 overflow: hidden 的盒子 —— 不能加到上面的盒子中,因为after和before不属于div!最后是两个元素的翻转效果:我们需要知道的是,为了性能考虑,我们最好是对整个盒子进行翻转,而不是对两个文字div附加动画

事实上,transform动画中的属性表示的含义更多的是“过渡多少”而不是“过渡到哪里”!

那么,这个层级关系就很明了了:

<!--伪元素装饰盒子--> <div class="pic_border"> <!--overflow-hidden盒子--> <div class="pic_box"> <!--transition过渡盒子--> <div class="pic_item"> <div class="pic_text">music</div> <div class="pic_back">此时此刻,非我莫属</div> </div> </div> </div>

按照上面所说,我们很容易为它添加对应的CSS:

.pic_border{ position: relative; } .pic_border::before{ content: ''; position: absolute; top: 50%; left: 0; width: 43vw; height: 1px; background-color: red; } .pic_border::after{ content: ''; position: absolute; top: 50%; right: 0; width: 43vw; height: 1px; background-color: red; } @media screen and (max-width: 1100px) { .pic_border::before,.pic_border::after{ width: 20vw; } } .pic_box{ display: inline-block; height: 70px; margin-left: calc(50% - 70px); overflow: hidden; perspective: 2000px; cursor: pointer; user-select: none; } .pic_item{ width: 100%; height: 100%; transform-style: preserve-3d; transition: all .7s ease; } .pic_text,.pic_back{ width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; } .pic_text{ transform: rotateX(0deg) translateZ(-21.9px); } .pic_back{ transform: rotateX(90deg) translateZ(-15px); } .pic_box:hover .pic_item{ transform: rotateX(-90deg); } .pic_box:active .pic_item{ transform: rotateX(-90deg); }

需要注意的是:3D效果是一定要有Z轴参与的! 不然会显得很“尴尬”


有了简单的上下翻滚,我们还可以实现“跟随鼠标上下左右翻滚”动画,就是所谓的“鼠标从哪里进入盒子,盒子就往哪个方向翻转” —— 有两种实现方式:

在最外层盒子中加四个方向的i或span标签,用来判断鼠标从哪里进入,JS控制盒子做对应的rotateX/Y;借助数学库与“matrix”: <div class="block" id="block"> <div class="face front"></div> <div class="face back"></div> <div class="face up"></div> <div class="face down"></div> <div class="face left"></div> <div class="face right"></div> </div> .block { position: absolute; transform-style: preserve-3d; width: 100px; height: 100px; transform-origin: 50px 50px; } .front { background: fuchsia; } .back { transform: translate3d(0, 0, 100px) rotateY(180deg); background: red; } .left { transform-origin: 100% 50% 0px; transform: rotateY(90deg); background: aqua; } .right { transform-origin: 0% 50% 0px; transform: rotateY(-90deg); background: blueviolet; } .up { transform-origin: 50% 0% 0px; transform: rotateX(90deg); background: darkorange; } .down { transform-origin: 50% 100% 0px; transform: rotateX(-90deg); background: darkviolet; }

为了便于观察,我们为让魔方格子旋转起来: 鼠标滑动分为左、右、上、下滑动,每种滑动对应一种方向的格子旋转。

从右往左:绕 Y 轴旋转 θ 角从左往右:绕 Y 轴旋转 -θ 角从上往下:绕 X 轴旋转 θ 角从下往上:绕 X 轴旋转 -θ 度

当然旋转需要有一个参照点,默认盒子中心。我们可以借助库函数将生成的矩阵转化为 CSS 中 transform 的 matrix3d 属性值。

var currentQ = {x:0, y:0, z:0, w:1}; var lastQ = {x:0, y:0, z:0, w:1}; var currentMatrix = matrix.identity(); var l = Math.sqrt(dx * dx + dy * dy); if(l <= 0) return; var x = dx / l, y = dy / l; var axis = {x: x, y: y, z: 0}; var q = matrix.fromAxisAndAngle(axis, l); currentQ = matrix.multiplyQuaternions(q, lastQ); currentMatrix = matrix.makeRotationFromQuaternion(currentQ);

通过上述方式我们计算出了当前旋转矩阵 currentMatrix,接下来,我们使用上面介绍的矩阵转化成对应 css 的函数,生成对应的 transform 属性:

// 将矩阵转化为transform matrix 属性值。 function matrix2css(m){ var style = 'matrix('; if(m.length == 16){ style = 'matrix3d(' } for(let i =0; i< m.length; i++){ style += m[i]; if(i !== m.length - 1){ style += ',' }else{ style +=')' } } return style; } var style = matrix2css(currentMatrix);

最后将生成的样式应用到魔方格子上:

document.querySelector('#block').style.transform = style;

这样就实现了一个美妙的动画盒子!


帧动画在canvas中的应用

除去CSS-transform和animation在项目中的大放异彩,canvas+CSS的动画方式也得到了很多人的支持!而canvas中实现动画的最好方式不是离屏技术、不是canvas动画库,而是帧动画!

我们通常通过requestAnimFrame控制一张图片上的显示区域的位置从而达到“伪动画”!

比如:

//调用方js部分内容 var starPic=new Image() starPic.src="上面图片地址" var lastTime,deltaTime; var stardog=new starObj() stardog.init() lastTime=Date.now() gameloop() function gameloop(){ window.requestAnimFrame(gameloop) var now=Date.now() deltaTime=now-lastTime lastTime=now drawStars() } //真正控制动画的js文件 var satrObj=function(){ this.x; this.y; this.picNo; this.timer; } starObj.prototype.init=function(){ this.x=Math.random()*630+100; //630:图片宽度 this.y=Math.random()*70+150; //70:图片高度 this.picNo=0; this.timer=0; } starObj.prototype.update=function(){ this.timer+=deltaTime; if(this.timer>50){ this.picNo+=1; this.picNo%=7; this.timer=0; } } starObj.prototype.draw=function(){ ctx.drawImage(starPic,0,0,this.picNo*70,70,this.x,this.y,70,70) } function drawStars(){ stardog.update(); stardog.draw(); }

毫无疑问的是:这种方式对UI和前端的结合开始有了要求。 (笔者前段时间研究支付宝春节活动发现:里面采用的也是“前端引入动画文件”的方式!)


以前用jQuery的animate()实现过一个 视频弹幕效果 的案例,这个用原生 JS+CSS的方式实现起来会比较麻烦。 但现在有了canvas,我封装了一个函数供各位使用:

/** el:需要弹幕的元素(此区域的最外层元素),需要加“#”或“.” text:弹幕文字 width:需要弹幕的元素(此区域的最外层元素)的宽 height:需要弹幕的元素(此区域的最外层元素)的高 step:可选,用于控制弹幕速度 */ function canvasTextAnim(el,text,width,height,step=5){ let canvas=document.createElement("canvas"); canvas.setAttribute('width',width); canvas.setAttribute('height',height); canvas.style.cssText="position:absolute;top:0;left:0;z-index:10000000"; document.querySelector(el).appendChild(canvas); let ctx=canvas.getContext('2d'); let w=canvas.width; let wid=w-1; let heigh=Math.random()*canvas.height+1; let stepd=Math.random()*step+2; ctx.beginPath(); setInterval(()=>{ ctx.clearRect(0,0,w,canvas.height); ctx.fillText(text,wid-stepd,heigh); wid-=stepd; if(wid<-ctx.measureText(text).width){ document.querySelector(el).removeChild(canvas); } },90) }

使用时每次都去调用这个函数即可,记得为参数el元素加上 position:relative; !


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #并且用起来几乎都得心应手