原生JS+CSS:实现吉祥物眼球跟随鼠标转动
前言
工作中一个小小的特效 ✨
本来想运用 perspective-origin
,最后发现不用那么高大上,如果有更好地实现方案欢迎评论区交流~
1.在线尝试
2.仓库地址
- Gitee: https://gitee.com/yuziikuko/eyes-mousemove.git
- GitHub: https://github.com/yuziikuko/Eyes_Mousemove.git
3.效果预览
(一)准备素材
- 一张固定宽高的吉祥物 png 图片,眼球区域挖空
- 一张等宽高的眼球图片,白色背景充当眼白
- 本文使用 阿里巴巴矢量图标库的素材,笔者自己用 PS 把眼球抠出来处理了一下,仅供演示用
钢笔工具 yyds!!!(破音
(二)搭建项目
不管三七二十一,先把猫猫头摆在页面正中间
<div class="container">
<div class="cat-block">
<img src="img/head.png" alt="cat-head" class="cat-head" />
</div>
</div>
* {
margin: 0;
padding: 0;
border: 0;
outline: 0;
box-sizing: border-box;
}
.container {
min-width: 1200px;
width: 100vw;
height: 100vh;
background-image: radial-gradient(rgb(128, 0, 0) 0%, rgb(0, 0, 0) 100%);
position: relative;
}
.cat-block {
width: 500px;
height: 500px;
position: relative;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.cat-block .cat-head {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
object-fit: contain;
}
再把眼球图层定位在猫猫头上方,层级顺序影响不大,因为等下要裁剪眼球
<div class="cat-block">
<img src="img/head.png" alt="cat-head" class="cat-head" />
<img src="img/eyes.png" alt="cat-eyes" class="cat-eyes" />
</div>
.cat-block .cat-head,
.cat-block .cat-eyes {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
object-fit: contain;
}
(三)创建镂空区域
想要让眼球只显示在猫猫头的镂空区域,其他区域隐藏,怎么做呢?🤔
如果你熟悉 PS 操作,其实这一步就是创建剪贴蒙版:
- 猫猫头在最上方
- 眼球图层在中间
- 眼球镂空区域在最下方
- 眼球图层相对镂空区域创建剪贴蒙版
Hmmmm...好像是个可行的思路,那就马上 上代码 上 Monica !😉
Monica:使用 CSS 和 SVG 创建一个镂空区域,以便 png1 只能在其中显示,可以使用
clip-path
属性和 SVGpath
元素来实现这一点。
(由于 svg 的 path 费脑子,这里就草率地用 circle 替代了
1.确定镂空区域
给猫猫戴上圆边眼镜,以猫猫图片左上角为原点,确定左右眼的镜片圆心坐标和半径
智能参考线 yyds!!!(破音
2.编写 svg 代码
<svg class="clip-path">
<circle
cx="160"
cy="265"
r="80"
stroke="red"
stroke-width="5"
></circle>
<circle
cx="318"
cy="265"
r="80"
stroke="red"
stroke-width="5"
></circle>
</svg>
.cat-block .cat-head,
.cat-block .cat-eyes,
.cat-block .clip-path {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
object-fit: contain;
}
3.定义镂空区域路径
确定左右眼的镂空区域后,只要把 circle
代码挪到 defs
标签中,配合 clip-path
就能定义裁剪路径
<svg class="clip-path">
<defs>
<clipPath id="cat_clip_path">
<circle cx="160" cy="265" r="80"></circle>
<circle cx="318" cy="265" r="80"></circle>
</clipPath>
</defs>
</svg>
(四)裁剪眼球图层
类比 PS 的创建剪贴蒙版,我们在上一步准备好了剪贴路径
接下来只要设置眼球图层相对剪贴路径创建蒙版即可,可以通过上一步中 clipPath
的 id
选中该路径
.cat-block .cat-eyes {
clip-path: url(#cat_clip_path);
}
裁剪后发现眼球在头部上层,所以稍稍调整一下顺序
.cat-block .cat-head,
.cat-block .cat-eyes,
.cat-block .clip-path {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
object-fit: contain;
z-index: 2;
}
.cat-block .cat-eyes {
z-index: 1;
clip-path: url(#cat_clip_path);
}
(五)让眼球动 👀
终于来到重头戏部分了!
首先当然是监听鼠标移动事件,老大哥 onmousemove
摩拳擦掌 ing...
眼球转动,一开始想的是 rotate
,不过多次尝试之后发现效果一般
- 单独设置
rotateX
,像是时钟摆动,pass - 设置
rotateX
、rotateY
,计算过程稍稍复杂,且很难调整,pass(绝对不是因为数学不好 - 设置
rotateX
、translateY
,眼球都脱离猫猫头了,pass
沉思片刻,既然眼球只能在镂空区域显示,那单独设置眼球根据鼠标指针偏移不就行了
修正偏移距离的计算公式其实是拼凑出来的,利用随鼠标指针变化的 xPos
和 yPos
,减去猫猫块的偏移使鼠标指针出现在眼球图层正中心,30 是一个一个数字慢慢试出来的,只要保证眼球(本例中的月牙)在眼眶内部转动即可
(虽然 low 但是不费脑子 😎,主打就是一个随性,有好的计算方法欢迎评论区交流~
let container = document.querySelector(".container");
let block = document.querySelector(".cat-block");
let eyes = document.querySelector(".cat-eyes");
container.addEventListener("mousemove", function (e) {
// 计算鼠标相对于容器左上角的偏移量
let xPos = e.clientX - container.offsetLeft;
let yPos = e.clientY - container.offsetTop;
// 修正偏移距离
let x = (xPos - block.offsetLeft) / 30;
let y = (yPos - block.offsetTop) / 30;
eyes.style.transform = `translateX(${x}px) translateY(${y}px)`;
});
(六)填补眼白
上一步虽然让眼球动起来了,但是效果 很怪!
沉思片刻 again,现在的效果是裁剪完的眼球图层转动,那只要让裁剪层和转动层分开不就行了
其实就是在转动的眼球图层上方再叠一层透明遮罩,裁剪的是遮罩,转动的是眼球图层
<div class="cat-eyes-rect">
<img src="img/eyes.png" alt="cat-eyes" class="cat-eyes" />
</div>
.cat-block .cat-eyes-rect {
clip-path: url(#cat_clip_path);
}
.cat-block .cat-eyes {
z-index: 1;
}
大功告成!🎉
转载自:https://juejin.cn/post/7241826575952019493