「兔了个兔」创意投稿大赛——动若脱兔转换视差效果

739 阅读4分钟

我正在参加「兔了个兔」创意投稿大赛,详情请看:「兔了个兔」创意投稿大赛

前言

今天为大家制作一个动若脱兔的转换视差效果,当鼠标在目标上左右移动时除了背景产生的位移视差效果外,里面的兔子也会跟着鼠标的位置来作出不同的动作

实现效果:

3.gif 码上掘金(建议点击去观看):

图片处理

先准备好四个不同动作兔子的图片和背景图

image.png

打开ps将新建一个1920 * 500的图层,将背景图拖进去铺满,然后分别将四个兔子放在指定的位置保存,最后就得到了四张带有背景和兔子的图片

image.png image.png

实现效果

html部分加入section标签,在里面分别加入弄好的图片设置不同的class,并用一个div标签将图片都包起来

<section>
    <div class="view">
      <img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a5c8e6a91c4641fab1cb04f1769ca09e~tplv-k3u1fbpfcp-zoom-1.image" class="sleep" alt="">
      <img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/407c35ce4b78485d9226e42a822911ee~tplv-k3u1fbpfcp-zoom-1.image" class="look" alt="">

      <img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b698b8b66e6448a69611d4b31a7079cf~tplv-k3u1fbpfcp-zoom-1.image" class="jump" alt="">
      <img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/032fbcb3beae4d04aaab7f269568c98e~tplv-k3u1fbpfcp-zoom-1.image" class="stop" alt="">
    </div>
</section>

然后来到css部分,为body标签设置内外边距为0,最小高度100vh,将里面的元素垂直居中

body {
  margin: 0;
  padding: 0;
  min-height: 100vh;
  display: flex;
  align-items: center;
  background-color: #fffefa;
}

加入section选择器,宽度设为100vw,高300px,设置相对定位,overflow设为hidden

然后加入section .view选择器,设置绝对定位,上下左右都为0,display设定为flex,justify-content和align-items都设为center

再将里面的图片重叠,display设为block,为了鼠标移动所产生的位移将图片宽度设大一点为120%,高度设为100%,但是图片比例不对,加入object-fit: cover图片就会按比例放大填满

section {
  width: 100vw;
  height: 300px;
  position: relative;
  overflow: hidden;
}
section .view{
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
  justify-content: center;
  align-items: center;
}
section img{
  position: absolute;
  display: block;
  width: 120%;
  height: 100%;
  object-fit: cover;
}

然后调整图片的前后排序,当鼠标从左至右移动时候,兔子会由睡觉,转换为站立张望,再转换跳跃,最后结束,所以class为sleep的图片在最顶,其他的依次排序

section .sleep {
  z-index: 9;
}

section .look {
  z-index: 8;
}

section .jump {
  z-index: 7;
}

section .stop {
  z-index: 6;
}

然后来到js部分,定义一个常量将section获取回来,为section新增mousemove监听鼠标移动的事件,在事件里将鼠标X的位置e.clientX除以浏览器视窗的宽度window.outerWidth的结果保存到变量percentage里,这样鼠标移到最左的时候percentage是0,最右是1,然后将percentage的值写到css中

const section = document.querySelector('section')
section.addEventListener('mousemove', (e) => {
  let percentage = e.clientX / window.outerWidth
  section.style.setProperty('--percentage', percentage)
})

首先处理背景图的位移效果,section .view选择器设置属性transform,设定值为水平移动translatex(),通过calc()计算,将percentage * 100px,即位移最大距离为100px

section .view {
  transform: translatex(calc(var(--percentage) * 100px));
}

下一步处理图片的变化了,只需调整透明度就可以达到想要的效果了

一开始四张图片都是显示的,只是section .sleep的层级比较高所以显示在最上面,例如section .sleep这张图片,当鼠标越往右移动的时候opacity的值就越小,percentage值为0.1及以上的时候,section .sleep这张图片就变透明了,就显示出section .look的图片,最后一张照片opacity只需设置为calc(1 + var(--percentage))就行了

section .sleep {
  z-index: 9;
  opacity: calc(1 - (var(--percentage) - 0.1 ) / 0.1); //percentage为0.1+时逐渐变透明
}

section .look {
  z-index: 8;
  opacity: calc(1 - (var(--percentage) - 0.25 ) / 0.25);//percentage为0.25+时逐渐变透明
}

section .jump {
  z-index: 7;
  opacity: calc(1 - (var(--percentage) - 0.4 ) / 0.4);//percentage为0.4+时逐渐变透明
}

section .stop {
  z-index: 6;
  opacity: calc(1 + var(--percentage)); //一直显示
}

当鼠标移出的时候会回复到原来的位置,新增一个mouseout事件,设置percentage为0.1,这样鼠标移出的时候就会复原

但是移出的时候比较生硬,需要加点动画过渡,为section里的每一个元素都添加transition过渡,但是会影响位移的效果,需要在鼠标移动的时候不套用过渡效果

所以得新增一个mouseenter事件,当鼠标进入的时候为section添加一个moving的class,在mouseout事件中再将moving移除,当section标签有moving的时候里面的元素都设置transition为none,就不会影响位移的效果了,完整的转换视差效果就完成了

section.addEventListener('mouseenter', (e) => {
  section.classList.add('moving')
})

section.addEventListener('mouseout', (e) => {
  section.classList.remove('moving')
  section.style.setProperty('--percentage', 0.1)
})
section .view,
section .sleep,
section .look,
section .jump,
section .stop {
  transition: .2s all ease-in;
}

section.moving .view,
section.moving .sleep,
section.moving .look,
section.moving .jump,
section.moving .stop {
  transition: none;
}