今天在看周刊的时候发现一个有趣的动画库 Atroposjs[1],它可以实现非常酷炫的 3D parallax hover effects(以前锤子官网首页 Banner 的同款效果)。先看实现效果:
这样的小动画往往会让人眼前一亮,忍不住多体验几次,产品曝光度就上来了。
Atroposjs[2] 代码很简洁,仅有 2KB, 零依赖还支持很多定制化配置。如果仅需要实现最基础的 3D 视差悬停效果,仅需几十行代码。
这篇文章,我们将来开发一个最基础的实现,完整代码可以看下面的【码上掘金】 或者我的 Codepen[3]
整体上这个动效分为两个部分,第一部分是鼠标 Hover 到卡片上时,卡片需要感知鼠标的位置,并做出相应的倾斜;第二部分是视差(Parallax) 效果,卡片内的元素根据”远近“的不同,移动速率不一样,以产生层次感。
Hover Effect 🖱
当鼠标在卡片上移动时,卡片会发生的形变。以卡片中心为远点将卡片划分为四个象限,结合 rotateX
和 rotateY
的方向可以得到在各个象限的旋转符号。
rotateX
, rotateY
的旋转角度(越来越大)
rotateX,rotateY 要看出 3D 效果,和
perspective
属性相关,它是用来设置观察者和 z=0 平面的距离的。处于 z > 0 位置的物体会比正常看起来更大,处于 z < 0 位置的物体回避正常看起来小。
在第一象限,rotateX
,rotateY
都是正数;第二象限 rotateX
是正数,rotateY
是负数,第三象限...
鼠标距离原点越近,卡片倾斜角度越小,距离越远,倾斜角度越大,如果单看 X 轴或 Y 轴,这个关系是线性的。还有一个特点是,鼠标纵方向移动时需要旋转 X 轴,横向移动时,旋转的是 Y 轴。分析完毕之后就可以开始写代码了。
// mousemove 事件
// 最大旋转角度
const maxRotate = 20
// 原点位置
const centerX = width / 2;
const centerY = height / 2;
// 鼠标位置相对卡片左上角的坐标
const offsetX = clientX - left
const offsetY = clientY - top
// 将和原点的距离线性折算成旋转角度
// 📢 X 方向移动旋转 Y 轴,Y 方向移动旋转 X 轴
let rotateX = (maxRotate * (offsetY - centerY)) / (centerY) * -1;
let rotateY = (maxRotate * (offsetX - centerX)) / (centerX);
// 设置 CSS Variables
this.style.setProperty('--rotateX', rotateX);
this.style.setProperty('--rotateY', rotateY);
复制代码
接着将旋转角度应用到卡片上。
.parallax-rotator {
position: relative;
transition: 300ms ease-out;
transform: rotateX(calc(var(--rotateX) * 1deg)) rotateY(calc(var(--rotateY) * 1deg));
}
复制代码
得到效果:
简简单单地几行代码就可以实现这么惊艳的效果,🐂 🍺!
Parallax Effect 😲
视差效果其实就是在 2D 的平面上,利用不同元素位置变化的速度不同,来模拟肉眼对物理世界远近感知的差异。观察者位移,距离近的物体位置变化大,而距离远的物体位置的变化小。
回到卡片上,我们将多张图片分层叠加在一起,给它们分别设置远近系数。
<img src="./images/bg.svg" style="--parallaxOffset: -4.5" />
<img src="./images/mountains.svg" style="--parallaxOffset: -2.5" />
<img src="./images/forest-back.svg" style="--parallaxOffset: 0" />
<img src="./images/forest-mid.svg" style="--parallaxOffset: 2" />
<img src="./images/forest-front.svg" style="--parallaxOffset: 4" />
复制代码
在鼠标移动时,通过远近系数控制物体的偏移,这里可以复用上面的 --rotateX
和 --rotateY
,计算出偏移量。需要注意旋转 Y 轴的时候需要 X 方向偏移,旋转 X 轴的时候需要 Y 方向偏移~
transform: translate3d(calc(var(--parallaxOffset) * var(--rotateY) / var(--maxRotate) * 1%),
calc(var(--parallaxOffset) * var(--rotateX) / var(--maxRotate) * -1%), 0);
复制代码
总结 📚
最后将两个部分合并在一起就可以得到酷炫吊炸天的效果了,在没动手实践过之前觉得这个效果很难,无从下手。梳理完之后核心只有寥寥数行代码。
文章中我只贴出核心代码,完整实现可以看下面的【码上掘金】 或者我的 Codepen[4]。如果你觉得这个实现还不错的话,欢迎点赞 ❤️ + 评论 + 收藏 + 关注~
文章中用到的素材都来自 Atroposjs[5] 官网,这个库还贴心地提供了 Vue/React/Svelte 的示例,感兴趣的盆友可以看看。
关于本文
作者:FESKY
https://juejin.cn/post/7126369893930237989
最后
欢迎关注【前端瓶子君】✿✿ヽ(°▽°)ノ✿
回复「算法」,加入前端编程源码算法群,每日一道面试题(工作日),第二天瓶子君都会很认真的解答哟!
回复「交流」,吹吹水、聊聊技术、吐吐槽!
回复「阅读」,每日刷刷高质量好文!
如果这篇文章对你有帮助,「在看」是最大的支持
》》面试官也在看的算法资料《《
“在看和转发”就是最大的支持