【BiliBili冬】头图日夜转换视差效果

3,501 阅读7分钟

大家好,我是 Steven,这几天终于感受到冬天真的要来了,我都有些感冒,所以大家要注意保暖喔。

BiliBili 也由秋季的头图换成了冬季的头图,看上去更加精美了,当游标左右移动的时候,除了背景和前景这棵树产生的位移视差效果外,背景也会转换为不同的天色,早上,下午,晚上这样:

制作的原理和秋季的版本也差不多,那我们今集就将这个冬天的头图实现出来啦。

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

在开始之前必须声明一下,这个教学里用到的图片和视频,都是取材自 BiliBili 官方网站,图片及视频版权归 BiliBili 所有,这里只用作教学演示用途。

HTML 的部份

打开 CodePen 编辑器,在 HTML 的部份加入 <header> 标签,然后分别加入早上的背景图,class 名为 morning;下午的背景图,class 名为 afternoon;而晚上的背景是 webm 的视频格式,用 <video> 标签加入,它用视频格式的原因是,里面有个火炉在闪闪发光:

class 名为 evening,以及窗框积雪效果的图片,class 名为 window-cover

再来另外三张图片,是不同天色下的树的变化,会放在画面的前方,与背景形成视差的效果。分别都加入 class,名为 morningafternoon 以及 evening

好,现在我们总共加入了 7 个元素,先将背景的部份用一个 <div> 组合起来,class 命名为 view

而树的部份同样用一个 <div> 组合起来,class 命名为 tree

CSS 的部份

HTML 的部份就来到这里,开始 CSS 的部份。加入 body 选择器,将 margin 设定为 0,然后加入 header 选择器,将高度设定为 160pxposition 设定为 relativeoverflow 设定为 hidden

然后要将 .view 以及 .tree 重叠,并且将内容置中,加入 header .view, header .tree 选择器,设定 positionabsolute,上右下左设定为 0;然后 display 设定为 flexjustify-contentalign-items 设定为 center

再将里面的图片与视频重叠,加入 header img, header video 选择器,position 设定为 absolutedisplay 设定为 block。为了支持位移,将宽度设定得大一点,例如 120%,高度设定为 100%,这样图片的比例是不对的,加入 object-fit 设定为 cover 图片就会按比例放大填满。

然后我们调整一下图片的前后排序,当游标由左至右移动的时候,会由早上,转换为下午,再转换为晚上,所以 .morning 应该在最顶,.afternoon 次之。

加入 header .morning 选择器,设定 z-index20,再加入 header .afternoon 选择器,设定 z-index10

注意因为 class 名称相同的原因,这里的排序设定其实也同时套用到树上,这也是我们想要的效果,因为早上的背景应该配合早上的树,如此类推。

JavaScript 的部份

好了,虽然 CSS 的部份还未完成,但我们暂时先跳到 JavaScript 的部份,这样更方便讲解接下来的步骤。

定义一个常量,将 header 获取回来。然后新增一个 mousemove 监听游标移动的事件,先来处理一下背景图和前景树的视差效果。按照我们一贯的作风,能交给 CSS 做的事,交给 CSS,尽量写少一些 JavaScript。

定义一个变量名为 percentage,将游标的 X 位置 e.clientX,除以浏览器视窗的宽度 window.outerWidth。这样当游标移到最左的时候是 0,移到最右的时候是 1,有了这个值,我们就可以将整个动画效果计算出来了。

通过 header.style.setProperty(),将 percentage 的值写入到 CSS 变量中,而这个 CSS 变量名为 --percentage,这样我们就可以在 CSS 中引用到这个动态值。

CSS 的调整

回到 CSS 的部份,首先处理背景图与前景树的移动视差效果。加入 header .view 以及 header .tree 选择器,设定背景 .viewtransform 属性,设定值是水平移动方向 translatex()

通过 var(--percentage) 将值获取回来,然后加入 calc() 将这个值乘以 100px,即是位移的最大距离是 100px。同样的设定套用到 .tree 里面,将前景的值调整为 50px。而前景应该是失焦的状态,加入 filter: blur(3px),就可以将它模糊化了。

下一步处理背景,由早上到晚上的变化。由于现在早上的图排在最前,下午的图排在中间,所以只需要调整它们的透明度,就可以达到想要的效果。

header .morning 内加入 opacity 属性,设定值同样可以通过 --percentage 计算出来。设定为 calc(),将 1 减去 --percentage0.25,再除以 0.25。这样图片就会在 --percentage0.25 时开始逐渐变为透明,然后在 header .afternoon 内套用同样的设定,将 0.25 更改为 0.5,这样图片就会在 --percentage0.5 时开始逐渐变为透明。

优化效果

现在效果已经基本完成了,不过还有可以优化的地方。我们会发现游标在不同的位置切入时,会突然跳一下。

这是由于我们固定了最左是早上的背景,最右是晚上的背景,这里可以做一个小修改,让它可以支持在任何一个切入点作为起始点。

在 JavaScript 的部份,定义一个变量名为 startingPoint,加入 mouseenter 事件监听器,将 startingPoint 赋值为 e.clientX,代表当游标进入这个 header 的时候,将它的 X 位置记录下来。

再调整一下 percentage 的计算公式,将 e.clientX 减去 startingPoint,再在最后加上 0.5,即默认在中间的位置。

回到 CSS 的部份,在 header 选择器内,为 --percentage 设定一个默认值为 0.5。现在我们会发现在任何一个点切入,都会由下午开始,这其实是我们想要的效果,因为需要配合下一个修改,就是当游标离开时,会回复到原来的位置。

再到 JavaScript 的部份,新增一个 mouseout 事件监听器,通过 header.style.setProperty(),将 --percentage 设定为 0.5

由于游标离开后 --percentage 会重置为 0.5,现在切入的时候效果就合理得多了。

再来为这个复位的动作加一些动画过渡,我们先想一想,哪些位置需要动画过渡。包括有位移的背景和前景,即是 .view.tree,以及有调整透明度的早上和下午,即是 .morning.afternoon

先加入这四个选择器为一组,然后设定 transition: .2s all ease-in

但却影响到移动时的效果,所以我们要做一些修改,让它在游标移动时不要套用 transition,复制这四个选择器,在 header 后都加上 .moving 这个 class,然后 transition 设定为 none,即是当 header.moving 这个 class 的时候,取消 transition 的设定。

回到 JavaScript 的部份,在 mouseenter 的时候加入 moving 这个 class,而在 mouseout 的时候移除 moving 这个 class

好了,还想调整多一个细节,就是这个晚上背景的窗框积雪,是在晚上背景出现后再出现的。要调整这个也很简单,回到 CSS 中,加入 header .window-cover 选择器,设定 opacitycalc()var(--percentage) 减去 0.9 再除以 0.1,这样窗框积雪就会在最后时才出现。

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

好了,细心的你一定会发现,没有做到下雪效果,是的,因为一来下雪效果是用 <canvas> 做的,JavaScript 的内容比较多,这一集主要想围绕 CSS 的技巧去讲解。其次就是,下雪效果可能没必要自己亲手去写的,网上面有很多做得很好的下雪效果了,当然如果想钻研 <canvas> 就另作别话,希望很快可以准备到有趣的 <canvas> 内容与大家分享。

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


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

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