原生JS+CSS:实现吉祥物眼球跟随鼠标转动

前言

工作中一个小小的特效 ✨

本来想运用 perspective-origin ,最后发现不用那么高大上,如果有更好地实现方案欢迎评论区交流~

1.在线尝试

CodeSandbox

2.仓库地址

3.效果预览

AnimateEffect.gif

(一)准备素材

  • 一张固定宽高的吉祥物 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 属性和 SVG path元素来实现这一点。

(由于 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 的创建剪贴蒙版,我们在上一步准备好了剪贴路径

接下来只要设置眼球图层相对剪贴路径创建蒙版即可,可以通过上一步中 clipPathid 选中该路径

.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
  • 设置 rotateXrotateY ,计算过程稍稍复杂,且很难调整,pass(绝对不是因为数学不好
  • 设置 rotateXtranslateY ,眼球都脱离猫猫头了,pass

沉思片刻,既然眼球只能在镂空区域显示,那单独设置眼球根据鼠标指针偏移不就行了

修正偏移距离的计算公式其实是拼凑出来的,利用随鼠标指针变化的 xPosyPos,减去猫猫块的偏移使鼠标指针出现在眼球图层正中心,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)`;
});

眼球跟随鼠标转动07.gif

(六)填补眼白

上一步虽然让眼球动起来了,但是效果 很怪!

沉思片刻 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;
}

大功告成!🎉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值