Bilibili 官网冬季的 banner 图吸引了我,一开始是中午图,鼠标左移浮现早上图,右移浮现晚上图,挺有意思
来实现一波
做之前先不要调试看 b 站的代码,自己先想想怎么实现,这样知识记得比较深
我们尽量使用 css 解决,js 弥补
比较明显的可以看到==早中晚三张22 33娘玩耍的图片==,浏览器调试可以发现还有==三张早中晚的树木图片,一张雪球图片、窗口积雪图片==
一共有 8 张图片资源,其中晚上图片是一段 webm 视频,因为有个小火炉在燃烧
把这些资源文件直接保存到本地
所有图片资源,都在头部位置,用==绝对定位==
默认展示是中午,早晚是鼠标经过才会出现,那么它们的层级关系可以这样定位:
对应早中晚的树木也应该是如此
重点:切换
鼠标移动过程中图片切换的效果,实质对应的是切换每张图片的==透明度 opacity==
设置了如上早中晚的层级关系后,我们来定一下左移和右移三个时间段的 opacity
上面两个过程可以知道,早上的 opacity 可以不用管,而中午和晚上的 opacity 都涉及到变化
切换的过程也涉及到图片的移动,可以使用==transform: translatex()==
鼠标移开 banner 图时,恢复成中午,有个过渡动画,可以使用==transition==
关键点:根据鼠标移动的距离计算 opacity
计算
在包裹 banner 的 div 容器样式表设置 --percentage 属性,默认为 0.5
而鼠标移动的距离,需要通过 js 计算
mouseenter、mousemove、mouseout 三个监听函数,动态计算出移动百分比,赋值到 --percentage 属性
图片的 ==transform、opacity== 属性需要应用到 --percentage 来计算数值
需要注意的是:
基本该说的点都在上面了,下面来展示一波代码
注:还有一个下雪的动画,需要用 canvas 实现,这里就没做了
html:
<div class="banner">
<div class="view">
<img
src="../../assets/bilibili/bilibili-winter-view-1.jpg"
class="morning"
/>
<img
src="../../assets/bilibili/bilibili-winter-view-2.jpg"
class="afternoon"
/>
<img
src="../../assets/bilibili/bilibili-winter-ball.png"
class="ball"
/>
<video autoplay loop muted class="evening">
<source
src="../../assets/bilibili/bilibili-winter-view-3.webm"
type="video/webm"
/>
</video>
<img
src="../../assets/bilibili/bilibili-winter-view-3-snow.png"
class="window-cover"
/>
</div>
<div class="tree">
<img
src="../../assets/bilibili/bilibili-winter-tree-1.png"
class="morning"
/>
<img
src="../../assets/bilibili/bilibili-winter-tree-2.png"
class="afternoon"
/>
<img
src="../../assets/bilibili/bilibili-winter-tree-3.png"
class="evening"
/>
</div>
</div>
css:
.banner {
min-height: 155px;
height: 9.375vw;
position: relative;
overflow: hidden;
--percentage: 0.5;
.view,
.tree {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
transition: 0.2s all ease-in;
}
.view {
transform: translatex(calc(var(--percentage) * 100px));
}
.tree {
transform: translatex(calc(var(--percentage) * 150px - 25px));
filter: blur(3px);
}
img,
video {
position: absolute;
height: 100%;
}
.evening {
transition: 0.2s all ease-in;
z-index: 20;
opacity: calc((0.5 - var(--percentage)) / 0.5);
}
.afternoon {
transition: 0.2s all ease-in;
z-index: 10;
opacity: calc(1 - (var(--percentage) - 0.5) / 0.5);
}
&.moving {
.afternoon,
.evening,
.ball,
.view,
.tree {
transition: none;
}
}
.ball {
transition: 0.2s all ease-in;
z-index: 10;
opacity: calc(1.5 - (var(--percentage) - 0.5) / 0.5);
transform: translate(calc(100px * var(--percentage)), 22px) rotate(calc(10deg * var(--percentage) + 5deg));
}
.window-cover {
z-index: 20;
opacity: calc(var(--percentage) * (-2));
}
}
js:
let startingPoint = 0
const header = document.querySelector('.banner')
header.addEventListener('mouseenter', (e) => {
startingPoint = e.clientX
header.classList.add('moving')
})
header.addEventListener('mouseout', (e) => {
header.classList.remove('moving')
header.style.setProperty('--percentage', 0.5)
})
header.addEventListener('mousemove', (e) => {
let percentage = ((startingPoint - e.clientX) / window.outerWidth) * 2 + 0.5
header.style.setProperty('--percentage', percentage)
})
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。