写点什么

HTML5+CSS3 高级动画的应用实践

用户头像
云小梦
关注
发布于: 2021 年 03 月 28 日

我们大概都知道 css 可以用来作平面旋转、扭曲、放大缩小、平移。。。并且用起来几乎都得心应手。

但目前来说,3D 效果的“高级”动画似乎更受欢迎一些,而且我们也确实需要。


-----


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


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


1. 首先,要实现这个功能,我们从外往里看:把文字所在部分看作一个盒子的话,前后两个横线并不属于这个盒子才对,那么,很自然就想到了—— ::after::before 伪元素;

2. 其次,两个文字分别在两个 div 上,那么就需要有一个可以附带 overflow: hidden 的盒子 —— 不能加到上面的盒子中,因为 after 和 before 不属于 div!

3. 最后是两个元素的翻转效果:我们需要知道的是,为了性能考虑,我们最好是对整个盒子进行翻转,而不是对两个文字 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 轴参与的! 不然会显得很“尴尬”


-----


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


1. 在最外层盒子中加四个方向的 i 或 span 标签,用来判断鼠标从哪里进入,JS 控制盒子做对应的 rotateX/Y;

2. 借助数学库与“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; !


发布于: 2021 年 03 月 28 日阅读数: 10
用户头像

云小梦

关注

求知若渴,虚心若愚 2019.05.11 加入

江湖人称“云小梦”。一个大前端路上还未“毕业”的“小学生”。爱好分享、执着探索、乐于开源;着迷于vue、node、css、可视化、前端智能化以及原生js技术。csdn链接:https://yunxiaomeng.blog.csdn.net/

评论

发布
暂无评论
HTML5+CSS3高级动画的应用实践