【BiliBili 秋】头图景深对焦效果

3,894 阅读4分钟

大家好,我是 Steven。

今期我们会介绍怎样实现 BiliBili 秋季 的那个顶部图片横幅效果,当游标移过去的时候,随着左右移动,会有景深和对焦的效果。

这个教程的视频版在 www.bilibili.com/video/BV1NZ… ,欢迎三连关注!


HTML 的部分

打开 CodePen 编辑器,在 HTML 的部份加入一个 <header> 标签,然后里面加入六个 <div>,每一个 <div> 里面加入一张图片。

这六张图片都是来自 BiliBili 的,图片版权归 BiliBili 所有,这里只用作教学用途。

我们先看看这六张图片,大小都一样的,是这个 Header Banner 不同的分层。将它们堆叠在一起,就可以组成一张完整的图片。

CSS 的部分

在 CSS 里,先加入 body 选择器,设定 margin0

加入 header 选择器,高度设定为 160pxposition 设定为 relativeoverflow 设定为 hidden。然后将里面的六个 <div> 重叠在一起,加入 header > div 选择器,positionabsolutetopleft 设定为 0,宽度和高度设定为 100%

我想将里面的图片上下左右置中,加入 display: flexjustify-contentalign-items 设定为 center,就可以了。

再加入 header > div > img 选择器,设定图片的样式。display 设定为 block,宽度设定为 110%,因为稍后图片会左右移动,为免穿帮,所以要将宽度加大一点,高度设定为 100%,加入 object-fit: cover,将图片按比例填满容器。

设定 CSS 变量

样式都设定好了,我们要再预留两个 CSS 变量,作为将图片左右移动,以及调整模糊度的功能。

加入 transform: translatex(),设定值是 var(--offset),以及 filter: blur(var(--blur))。那么我们接下来,就会通过 JavaScript,设定 --offset--blur 的值,从而达到动画效果。

可以先设定 --offset 的预设值为 0px,而 --blur 的预设值为 2px

JavaScript 的部分

来到 JavaScript 的部份,先定义一个常量 images,获取所有图片回来。

然后在 header 那里,加入 addEventListener 监听 mousemove 游标移动事件。首先要计算移动的百份比,定义一个变量 percentage,将 e.clientX 除以 window.outerWidth,这样当游标移到最左时是 0,移到最右时是 1。然后定义变量 offset,定义分层图片位置的距离,除了移动距离,还有模糊度,接下来就要将这些值套用到每一层的图片上。

先加入 for of 回圈,将所有图片获取出来,然后将 offset *= 1.3,即是越后的图片,位移就会越多。再计算一下分层模糊度的值,这个算是我花最多时间思考怎样做的地方,原因是… 中学没有把数学学好

这里要做到的是,游标在中间的时候,第 3 和第 4 张分层图片的模糊度最低,趋近于 0,而第 2 和第 5 张图片模糊度较高,第 1 和第 6 张模糊度最高;而游标在右边的时候,第 6 张图片模糊度趋近于 0,越往左的图片,模糊度越高。

这其实是一条很简单的数学公式,但就一直也想不起是什么公式,在想放弃前一秒终于想到,就是曲线的公式啦。

y = x^2 * 20 大概就是我们想达到的效果,所以,原来学好数学是很重要的呢。

回到这里,定义变量 blurValue,将 index / images.length 减去 percentage 作为公式里的 x,然后将它乘以 2 次方,再乘以 blur,即是 20

最后,通过 setProperty(),分别将位移和模糊度的值设定到 --offset--blur 这两个 CSS 变量里。

我们来看看这个案例的完成效果

对了,BiliBili 的版本还有一个效果,就是她会眨眼,这个原理也很简单,他们准备了几张眨眼过程的图片,只需要使用 setInterval()setTimeout() 定时将图片转换就可以了,在这就不特别介绍了。

以上,就是今集要介绍的全部内容。


这个案例的源代码在 codepen.io/stevenlei/p…

你的支持是我的动力,请关注 CodingStartup 起码课,我们一起加油!