生活随笔
收集整理的這篇文章主要介紹了
仿B站首页头部动画的实现
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
B站的前端樣式一直是我學習和模仿的對象,特別是它的首頁頭部動畫,可以隨著鼠標的移動進行場景的變化,很酷,所以我對它進行了大體上的模仿
廢話不多說,先看效果
仿B站首頁動畫演示
視頻打不開點擊這里
完整代碼如下:這里將css、js、html代碼整合到一塊去了,大家也可以去碼云自行下載
碼云地址
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document
</title><style>* {margin: 0;padding: 0;}.bili-banner {margin: 0 auto;position: relative;z-index: 0;min-height: 155px;height: 9.375vw;min-width: 999px;background-color: pink;display: flex;justify-content: center;background-repeat: no-repeat;background-position: center 0;background-size: cover;}.animateds-banner {position: absolute;top: 0;bottom: 0;left: 0;right: 0;overflow: hidden;}.animateds-banner > .layer {position: absolute;left: 0;top: 0;height: 100%;width: 100%;display: flex;align-items: center;justify-content: center;}</style>
</head>
<body><div class="bili-banner"><div class="animateds-banner"><div class="layer"><img src="img/1.png" height="184" data-height="360" data-width="9666" width="4957" /></div><div class="layer"><img src="img/2.png" height="184" data-height="360" data-width="9666" width="4957" /></div><div class="layer"><img src="img/3.png" height="166" data-height="360" data-width="3523" width="1626" /></div><div class="layer"><img src="img/4.png" height="180" data-height="360" data-width="2938" width="1476" /></div><div class="layer"><img src="img/5.png" height="64" data-height="139" data-width="556" width="256" /></div><div class="layer"><img src="img/6.png" height="86" data-height="302" data-width="734" width="210" /></div><div class="layer"><img src="img/7.png" height="129" data-height="180" data-width="1757" width="1261" /></div><div class="layer"><img src="img/8.png" height="83" data-height="116" data-width="1757" width="1261" /></div><div class="layer"><img src="img/9.png" height="141" data-height="346" data-width="497" width="203" /></div><div class="layer"><img src="img/10.png" height="105" data-height="256" data-width="146" width="59" /></div><div class="layer"><img src="img/11.png" height="117" data-height="254" data-width="602" width="277" /></div><div class="layer"><img src="img/12.png" height="184" data-height="360" data-width="4277" width="2193" /></div><div class="layer"><img src="img/13.png" height="150" data-height="327" data-width="933" width="430" /></div><div class="layer"><img src="img/14.png" height="217" data-height="353" data-width="740" width="455" /></div><div class="layer"><img src="img/15.png" height="184" data-height="360" data-width="1916" width="982" /></div><canvas width="1677" height="159" style="position: absolute; top: 0px; left: 0px; "></canvas></div></div><script>let banner = document.querySelector('.animateds-banner')let layers = document.querySelectorAll('.layer')let layers_data = [{ translateX: 0, translateY: -15.3871, filter_blur: 0, opacity: 1},{ translateX: 1128.39, translateY: 0, filter_blur: 0, opacity: 1},{ translateX: 692.419, translateY: 0, filter_blur: 0, opacity: 1},{ translateX: -653.439, translateY: 0, filter_blur: 0, opacity: 1},{ translateX: 623.177, translateY: 46.1613, filter_blur: 0, opacity: 1},{ translateX: 258.503, translateY: 37.3394, filter_blur: 0, opacity: 0},{ translateX: 114.89, translateY: 14.3613, filter_blur: 0, opacity: 1},{ translateX: -359.032, translateY: 50.2645, filter_blur: 0, opacity: 1},{ translateX: -246.194, translateY: 16.4129, filter_blur: 0, opacity: 0},{ translateX: -348.774, translateY: 32.8258, filter_blur: 0, opacity: 0},{ translateX: -92.3226, translateY: 13.8484, filter_blur: 0, opacity: 1},{ translateX: 102.581, translateY: 0, filter_blur: 0, opacity: 1},{ translateX: 221.574, translateY: 13.8484, filter_blur: 0, opacity: 1},{ translateX: 2154.19, translateY: 0, filter_blur: 2, opacity: 1},{ translateX: -1025.81, translateY: 0, filter_blur: 1, opacity: 1},]let init = function() {for (const k in layers) {if (Object.hasOwnProperty.call(layers, k)) {const element = layers[k]let element_data = layers_data[k]element.children[0].style = 'transform: scale(1) translate('+ element_data.translateX +'px,'+ element_data.translateY +'px) rotate(0deg); filter: blur('+ element_data.filter_blur +'px); opacity:'+ element_data.opacity +';'}}}let x_first = 0let x_now = 0let x_offset = 0banner.addEventListener("mouseover", function(e) {x_first = e.clientX})banner.addEventListener("mousemove", function(e) {x_now = e.clientXx_offset = x_first - x_nowfor (const k in layers) {if (Object.hasOwnProperty.call(layers, k)) {let level = (15 - parseInt(k)) * 0.5;const element = layers[k]const element_data = layers_data[k]let new_translateX = element_data.translateX + x_offset / levellet new_opacity = element_data.opacityif (k == 5 && x_offset < 0) {new_opacity = 0.333} else if ((k == 8 || k == 9) && x_offset > 0) {new_opacity = 0.44} else {new_opacity = element_data.opacity}element.children[0].style = `transform: scale(1) translate( ${new_translateX}px, ${element_data.translateY}px ) rotate(0deg);filter: blur(${element_data.filter_blur}px);opacity: ${new_opacity};`}}})banner.addEventListener("mouseout", function() {init()})window.onload = function() {init()}</script>
</body>
</html>
我就在這里講講我的思路吧,因為效果也不是完全一致的,就說一下在寫代碼過程中遇到的一些問題
首先,我先看的B站源代碼,沒有找到控制該效果的js文件,所以就先將其html框架copy下來了,當然,它的樣式是這樣的
我的代碼在它的基礎上將img標簽中的內聯樣式進行了提取,至于為什么要這樣做,一會會說明,css樣式是一樣的,就直接copy引入即可去B站首頁觀察這個效果和它的源代碼的時候,我發現了以下幾點:首先,這一張一張的圖片的移動速度肯定是不相同的,第二,在我鼠標移動進去這個區域的時候,圖片的translate的值是不變的,也就是說,鼠標第一次進入這個區域的時候,這個位置就是移動的初始位置,移動過程中,改變相應速率的translate的值,第三,鼠標移出以后,恢復到原來的狀態有了以上信息,就開始著手做了,首先,為了將所有的圖片組合成一個靜態頁面,就免不了對圖片的tanslate的值進行相應的改變,有的圖片改變X,有的圖片同時改變X和Y,而鼠標移動的過程,只需要改變translateX的值就行,所以將img的內聯樣式提取出來成為一個對象數組,這樣讀取很簡單,因為初始化的數據只在一開始呈現頁面時使用
let layers_data
= [{ translateX
: 0, translateY
: -15.3871, filter_blur
: 0, opacity
: 1},{ translateX
: 1128.39, translateY
: 0, filter_blur
: 0, opacity
: 1},{ translateX
: 692.419, translateY
: 0, filter_blur
: 0, opacity
: 1},{ translateX
: -653.439, translateY
: 0, filter_blur
: 0, opacity
: 1},{ translateX
: 623.177, translateY
: 46.1613, filter_blur
: 0, opacity
: 1},{ translateX
: 258.503, translateY
: 37.3394, filter_blur
: 0, opacity
: 0},{ translateX
: 114.89, translateY
: 14.3613, filter_blur
: 0, opacity
: 1},{ translateX
: -359.032, translateY
: 50.2645, filter_blur
: 0, opacity
: 1},{ translateX
: -246.194, translateY
: 16.4129, filter_blur
: 0, opacity
: 0},{ translateX
: -348.774, translateY
: 32.8258, filter_blur
: 0, opacity
: 0},{ translateX
: -92.3226, translateY
: 13.8484, filter_blur
: 0, opacity
: 1},{ translateX
: 102.581, translateY
: 0, filter_blur
: 0, opacity
: 1},{ translateX
: 221.574, translateY
: 13.8484, filter_blur
: 0, opacity
: 1},{ translateX
: 2154.19, translateY
: 0, filter_blur
: 2, opacity
: 1},{ translateX
: -1025.81, translateY
: 0, filter_blur
: 1, opacity
: 1},
]
4.給每一個圖層,也就是每個img標簽賦值(for in循環)就可以得到所有圖層結合的靜態頁面,我將這個過程封裝到了初始化函數中,因為鼠標移開效果復原也是相同的操作,所以直接調用init函數即可,同時注意在給樣式重新賦值的時候,有兩種寫法,我個人比較喜歡模板字符串,支持換行,然后數據拼接也比較簡潔易懂,鼠標移出,恢復原狀,那么也調用一次init函數
let init = function() {for (const k
in layers
) {if (Object
.hasOwnProperty
.call(layers
, k
)) {const element
= layers
[k
]let element_data
= layers_data
[k
]element
.children
[0].style
= 'transform: scale(1) translate('+ element_data
.translateX
+'px,'+ element_data
.translateY
+'px) rotate(0deg); filter: blur('+ element_data
.filter_blur
+'px); opacity:'+ element_data
.opacity
+';'}}}
banner
.addEventListener("mouseout", function() {init()
})
5.靜態頁面弄好了以后,就可以給不同的圖層賦值不同的移動速率了,鼠標移動的這個操作分為兩個過程,第一,鼠標首次到達該區域,第二,鼠標移動。
鼠標剛到該區域的時候,是初始化的位置,無需任何操作,只需記錄下鼠標的初始位置x_first即可,后面的操作根據這個初始位置進行translateX的動態賦值
banner
.addEventListener("mouseover", function(e
) {x_first
= e
.clientX
})
鼠標移動過程中,x_new記錄當前鼠標的位置,x_offset = x_first - x_new代表鼠標移動的位移,左移offset大于0,右移offset小于0,給每個圖層的變化添加不同的層級level,這樣就實現了不同圖層具有不同的速率
let level
= (15 - parseInt(k
)) * 0.5;
let new_translateX
= element_data
.translateX
+ x_offset
/ level
還有一些細節就是,B站的第六張圖片向右移動透明度逐漸增加,向左保持透明也就是opacity為0,第九、十章圖片效果相反,所以添加了一些判斷代碼,注意:k是索引,從0開始,所以第六張圖片的k是5,還有一個問題我沒有解決的就是,這三張特殊的圖片的opacity是逐漸變化的,而我沒有找到最合適的效果,所以給他們設定了一個固定值0.333和0.44,目的達到了反正
if (k
== 5 && x_offset
< 0) {new_opacity
= 0.333
} else if ((k
== 8 || k
== 9) && x_offset
> 0) {new_opacity
= 0.44
} else {new_opacity
= element_data
.opacity
}
然后就是修改img內聯樣式translateX的值
element
.children
[0].style
= `transform: scale(1) translate( ${new_translateX}px, ${element_data.translateY}px ) rotate(0deg);filter: blur(${element_data.filter_blur}px);opacity: ${new_opacity};`
這里,element不是img標簽,而是img標簽外面的div,所以通過.children[0]獲取到img元素,進而改變其樣式值
到這里,操作就完成了,然后,有什么意見,歡迎大家指正小白,畢竟啊,我是要成為代碼王的男人,會虛心接受大家的指導的
總結
以上是生活随笔為你收集整理的仿B站首页头部动画的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。