大家好,我是 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,名为 morning、afternoon 以及 evening。
好,现在我们总共加入了 7 个元素,先将背景的部份用一个 <div> 组合起来,class 命名为 view:
而树的部份同样用一个 <div> 组合起来,class 命名为 tree:
CSS 的部份
HTML 的部份就来到这里,开始 CSS 的部份。加入 body 选择器,将 margin 设定为 0,然后加入 header 选择器,将高度设定为 160px,position 设定为 relative,overflow 设定为 hidden。
然后要将 .view 以及 .tree 重叠,并且将内容置中,加入 header .view, header .tree 选择器,设定 position 为 absolute,上右下左设定为 0;然后 display 设定为 flex,justify-content 与 align-items 设定为 center。
再将里面的图片与视频重叠,加入 header img, header video 选择器,position 设定为 absolute,display 设定为 block。为了支持位移,将宽度设定得大一点,例如 120%,高度设定为 100%,这样图片的比例是不对的,加入 object-fit 设定为 cover 图片就会按比例放大填满。
然后我们调整一下图片的前后排序,当游标由左至右移动的时候,会由早上,转换为下午,再转换为晚上,所以 .morning 应该在最顶,.afternoon 次之。
加入 header .morning 选择器,设定 z-index 为 20,再加入 header .afternoon 选择器,设定 z-index 为 10。
注意因为 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 选择器,设定背景 .view 的 transform 属性,设定值是水平移动方向 translatex()。
通过 var(--percentage) 将值获取回来,然后加入 calc() 将这个值乘以 100px,即是位移的最大距离是 100px。同样的设定套用到 .tree 里面,将前景的值调整为 50px。而前景应该是失焦的状态,加入 filter: blur(3px),就可以将它模糊化了。
下一步处理背景,由早上到晚上的变化。由于现在早上的图排在最前,下午的图排在中间,所以只需要调整它们的透明度,就可以达到想要的效果。
在 header .morning 内加入 opacity 属性,设定值同样可以通过 --percentage 计算出来。设定为 calc(),将 1 减去 --percentage 减 0.25,再除以 0.25。这样图片就会在 --percentage 在 0.25 时开始逐渐变为透明,然后在 header .afternoon 内套用同样的设定,将 0.25 更改为 0.5,这样图片就会在 --percentage 在 0.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 选择器,设定 opacity 为 calc(),var(--percentage) 减去 0.9 再除以 0.1,这样窗框积雪就会在最后时才出现。
我们来看看这个案例的完成效果
好了,细心的你一定会发现,没有做到下雪效果,是的,因为一来下雪效果是用 <canvas> 做的,JavaScript 的内容比较多,这一集主要想围绕 CSS 的技巧去讲解。其次就是,下雪效果可能没必要自己亲手去写的,网上面有很多做得很好的下雪效果了,当然如果想钻研 <canvas> 就另作别话,希望很快可以准备到有趣的 <canvas> 内容与大家分享。
以上,就是今集要介绍的全部内容。
这个案例的源代码在 codepen.io/stevenlei/p…
你的支持是我的动力,请关注 CodingStartup 起码课,我们一起加油!
- B站: space.bilibili.com/451368848
- YouTube: youtube.com/codingstart…
- 掘金: juejin.cn/user/249773…