B站顶部的图片跟随效果感觉挺有意思的,具体为多张图片和视频根据鼠标位置实现上下左右移动,鼠标移开后恢复原样。
好了废话不多说,直接上代码,代码里有注释,也可以复制代码到本地查看效果。
图片/视频/完整代码资源可以去仓库下载
html
<div class="animated-banner" id="scene">
<!-- 图片 -->
<div class="layer"><img src="1.webp"></div>
<div class="layer"><img src="2.webp"></div>
<div class="layer"><img src="3.webp"></div>
<div class="layer"><img src="4.webp"></div>
<div class="layer"><img src="5.webp"></div>
<div class="layer"><img src="6.webp"></div>
<div class="layer"><img src="7.webp"></div>
<div class="layer"><img src="8.webp"></div>
<div class="layer"><img src="9.webp"></div>
<div class="layer"><img src="10.webp"></div>
<div class="layer"><img src="11.webp"></div>
<div class="layer"><img src="12.webp"></div>
<div class="layer"><img src="13.webp"></div>
<!-- 视频 设置静音 自动播放 -->
<div class="layer">
<video src="14.webm" loop playsinline width="200" height="500" autoplay muted
style="object-fit: cover; height: 500px; width: 200px; transform: translate(400px, 0px) rotate(0deg) scale(1); opacity: 1;">
</video>
</div>
<div class="layer"><img src="15.webp"></div>
<div class="layer"><img src="16.webp"></div>
<div class="layer"><img src="17.webp"></div>
<div class="layer"><img src="18.webp"></div>
<div class="layer"><img src="19.webp"></div>
<!-- 视频 设置静音 自动播放 -->
<div class="layer">
<video src="20.webm" loop playsinline width="200" height="500" autoplay muted
style="object-fit: cover; height: 500px; width: 200px; transform: translate(170px, 0px) rotate(0deg) scale(1); opacity: 1;">
</video>
</div>
<!-- 视频 设置静音 自动播放 -->
<div class="layer">
<video src="21.webm" loop playsinline width="200" height="500" autoplay muted
style="object-fit: cover; height: 500px; width: 200px; transform: translate(-600px, 0px) rotate(0deg) scale(1); opacity: 1;">
</video>
</div>
</div>
css
* {
margin: 0;
padding: 0;
}
body {
box-sizing: border-box;
}
.animated-banner {
display: flex;
justify-content: center;
margin: 0 auto;
min-width: 1000px;
min-height: 155px;
height: 9.375vw;
max-height: 240px;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
}
.layer {
position: absolute;
left: -150px;
top: 0;
height: 100%;
/* 宽度比视口宽300像素 防止左右滑动看见图片栅栏中断的情况*/
width: calc(100vw + 300px);
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
/* 添加平滑过渡效果 */
transition: transform 0.1s ease;
}
img {
width: 100%;
height: 100%;
}
js
document.addEventListener('DOMContentLoaded', () => {
const banner = document.querySelector('.animated-banner');
const layers = document.querySelectorAll('.layer');
// 数组的长度 == 元素个数
const movementFactor = Array.from({ length: layers.length }, (_, i) => (i + 1) * 0.3);
let isMouseInside = false; // 用于标记鼠标是否在banner内
let lastMouseX = 0; // 上一次鼠标X坐标
const handleMouseMove = (event) => {
if (!isMouseInside) return; // 鼠标尚未进入区域时不做处理
const mouseX = event.clientX - banner.getBoundingClientRect().left; // 计算鼠标相对banner的X位置
const bannerWidth = banner.offsetWidth;
// 计算相对移动量
const deltaX = mouseX - lastMouseX;
// console.log(deltaX);
// 只有在鼠标位置发生变化时才进行位置调整
if (Math.abs(deltaX) > 1) {
layers.forEach((layer, index) => {
const movementX = deltaX * movementFactor[index] / 50;
if (index == 16) {//这个水滴是斜向移动的 水滴移动的范围好像比背景和人物小点 所以除2
layer.style.transform = `translate(${movementX / 2}px,${movementX / 2}px)`;
} else if (index == 9 || index == 10) {//这个水滴是上下移动的
layer.style.transform = `translateY(${movementX / 2}px)`;
} else if (index == 4) {//这张小鲸鱼图片是反着移动的把movementX值改为负的
layer.style.transform = `translateX(${-movementX}px)`;
} else {
layer.style.transform = `translateX(${movementX}px)`;
}
});
}
}
const handleMouseEnter = (event) => {
isMouseInside = true; // 鼠标进入时标记为true
lastMouseX = event.clientX - banner.getBoundingClientRect().left; // 初始化上一次的鼠标位置为当前进入位置
layers.forEach(layer => {
layer.style.transition = 'none'; // 鼠标进入时禁用过渡效果
});
};
const handleMouseLeave = () => {
isMouseInside = false; // 鼠标离开时标记为false
layers.forEach(layer => {
layer.style.transition = 'transform 0.5s ease'; // 恢复过渡效果
layer.style.transform = `translateX(0px)`; // 恢复到初始位置
});
};
banner.addEventListener('mousemove', handleMouseMove);
banner.addEventListener('mouseenter', handleMouseEnter);
banner.addEventListener('mouseleave', handleMouseLeave);
});