3D 視差效果

圖片描述

前一週敢玩新版PC端上線,其中原創視頻封面用的就是上圖的效果,下面詳細說一下怎麼實現css

原由

這個效果有着相對較好的用戶體驗,在 hover 的基礎上又有了與用戶交互的體驗,彷彿用戶一直在不一樣角度按壓這張圖片。html

固然這個效果早就有人在寫並用於官網了,感興趣能夠去錘子官網,看下輪播圖的鼠標交互效果。css3

基本思路

單藉助 CSS3 的 hover 不足以支配這個效果,JS 方案考慮如下步驟瀏覽器

  1. 綁定鼠標事件(mouseover),綁定離開事件(mouseleave)
  2. 判斷鼠標相對於圖片的位置
  3. 計算出應該翻轉(rotate)的角度,同時改變陰影的方向
  4. 將圖片復位

這裏涉及 CSS3 的一個比較少用的屬性 perspectivebabel

MDN: perspective 屬性指定了觀察者與 z = 0 平面的距離,使具備三維位置變換的元素產生透視效果。z > 0 的三維元素比正常大,而 z < 0 時則比正常小,大小程度由該屬性的值決定。

深刻了解去看這個文章CSS3 Transform 的 perspective 屬性,時間比較久可是很經典,除了兼容性描述有變其它描述很準確。動畫

開始構建

html:this

<div class="avatar"></div>

css:url

.avatar {
  width: 300px;
  height: 300px;
  margin: 50px auto;

  background: url('http://7xr2s7.com1.z0.glb.clouddn.com/avatar.jpg');
  background-size: contain;

  transition: all .3s linear;
  transform-origin: 50%;
}

js:spa

let el = document.querySelector('.avatar')

el.addEventListener('mousemove', (e) => {
  let thisPX = el.getBoundingClientRect().left
  let thisPY = el.getBoundingClientRect().top
  let boxWidth = el.getBoundingClientRect().width
  let boxHeight = el.getBoundingClientRect().height

  let mouseX = e.pageX - thisPX
  let mouseY = e.pageY - thisPY
  let X
  let Y

  X = mouseX - boxWidth / 2
  Y = boxHeight / 2 - mouseY

  el.style.transform = `perspective(300px) rotateY(${X / 10}deg) rotateX(${Y / 10}deg)`
  el.style.boxShadow = `${-X / 20}px ${Y / 20}px 50px rgba(0, 0, 0, 0.3)`
})


el.addEventListener('mouseleave', () => {
  el.style.transform = `perspective(300px) rotateY(0deg) rotateX(0deg)`
  el.style.boxShadow = ''
})

以上代碼看似沒什麼問題,也許你在新版本瀏覽器(無需babel)已經順利執行了,可是這裏有一個坑。code

除非你能肯定你的圖片在一屏內,就是說你的 body 最大高度就是窗口高度,否則 let mouseY = e.pageY - thisPY 這句計算出來的不必定是真實的鼠標偏移量,而是加上滾動調偏移後的值。

解決辦法就是

let scrollTop = document.documentElement.scrollTop + document.body.scrollTop  //計算滾動高度

let mouseY = e.pageY - scrollTop - thisPY  //減去滾動高度

通常的項目考慮到這就能夠了,若是你的項目存在 X 軸上的偏移計算原理相同,減去偏移量。

實例

我本身的代碼放在了 codepen,以下

https://codepen.io/orangexc/p...

另外最近發如今 codepen 上的一個項目,在熱門榜單上,基本思路是同樣的只不過換了種方式去寫,很不錯的例子,對於須要多個元素循環綁定的狀況很好用。

https://codepen.io/PavelDoGre...

注:此種方法規避了高度差計算的問題,由於是基於 offsetX(做用元素的偏移量), 推薦使用

總結

JS 動畫考慮的會相對多一些,能夠獲取寬高及鼠標位置(方法多樣),根據鼠標位置能夠計算出動畫的對應效果,選擇合適的且兼容性好的代碼很關鍵

文章出自 orange 的 我的博客 http://orangexc.xyz/
相關文章
相關標籤/搜索