bilibili动态背景

bilibili 动态背景 winter || autumn || spring,刷新随机顶部 cover,本篇不做教程,仅作为记录艰辛的过程 📝

本来集成成了好几个 pug 结果发现并不能结构化引入,最后还是变成了 js 操作,难受难受,果然写习惯了 vue, react 再回来就不熟练了

坎坷的失败品

本来拆分出来了了以下几个 pug,结果发现完全用不了

autumn.pug

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.blqbanner.mobile-hidden
div
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/autumn/bilibili-autumn-1.webp')
div
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/autumn/bilibili-autumn-2.png')
div
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/autumn/bilibili-autumn-3.png')
div
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/autumn/bilibili-autumn-4.png')
div
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/autumn/bilibili-autumn-5.png')
div
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/autumn/bilibili-autumn-6.png')

link(rel="stylesheet", href=url_for("/css/biliBg/autumn/autumn.css"))
script(src=url_for("/js/biliBg/autumn/autumn.js"))

spring.pug

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
.bili-banner
.animated-banner
//- 背景
.layer
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/bg1.png', data-height='360', data-width='9666', height='180', width='4833', style='transform: scale(1) translate(0px, -15px) rotate(0deg); opacity: 1;')
//- 左山
.layer
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/bg2.png', data-height='360', data-width='9666', height='180', width='4833', style='transform: scale(1) translate(1100px, 0px) rotate(0deg); opacity: 1;')
//- 右山
.layer
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/bg3.png', data-height='360', data-width='3523', height='162', width='1585', style='transform: scale(1) translate(675px, 0px) rotate(0deg); opacity: 1;')
//- 左桥
.layer
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/bg4.png', data-height='360', data-width='2938', height='176', width='1439', style='transform: scale(1) translate(-637px, 0px) rotate(0deg); opacity: 1;')
//- 右船
.layer
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/bg5.png', data-height='139', data-width='556', height='62', width='250', style='transform: scale(1) translate(607.5px, 45px) rotate(0deg); opacity: 1;')
//- 开船人物
.layer
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/p4.png', data-height='302', data-width='734', height='84', width='205', style='transform: scale(1) translate(252px, 36.4px) rotate(0deg); opacity: 0;')
//- 中草坪+树
.layer
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/bg6.png', data-height='180', data-width='1757', height='125', width='1229', style='transform: scale(1) translate(112px, 25px) rotate(0deg); opacity: 1;')
//- 中草坪+风筝
.layer
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/bg7.png', data-height='116', data-width='1757', height='81', width='1229', style='transform: scale(1) translate(-350px, 49px) rotate(0deg); opacity: 1;')
//- 人物
.layer
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/p2.png', data-height='346', data-width='497', height='138', width='198', style='transform: scale(1) translate(-240px, 16px) rotate(0deg); opacity: 0;')
//- 人物
.layer
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/p1.png', data-height='256', data-width='146', height='102', width='58', style='transform: scale(1) translate(-340px, 32px) rotate(0deg); opacity: 0;')
//- 中树
.layer
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/t1.png', data-height='254', data-width='602', height='114', width='270', style='transform: scale(1) translate(-90px, 13.5px) rotate(0deg); opacity: 1;')
//- 中草坪+树
.layer
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/bg8.png', data-height='360', data-width='4277', height='180', width='2138', style='transform: scale(1) translate(100px, 0px) rotate(0deg); opacity: 1;')
//- 中人物
.layer
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/p3.png', data-height='327', data-width='933', height='147', width='419', style='transform: scale(1) translate(216px, 13.5px) rotate(0deg); opacity: 1;')
//- 右树
.layer
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/t3.png', data-height='353', data-width='740', height='211', width='444', style='transform: scale(1) translate(2100px, 0px) rotate(0deg); filter: blur(2px); opacity: 1;')
//- 左树
.layer
img(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/t2.png', data-height='360', data-width='1916', height='180', width='958', style='transform: scale(1) translate(-1000px, 0px) rotate(0deg); filter: blur(1px); opacity: 1;')
canvas#springCanvas(width='1519', height='155', style='position: absolute; top: 0px; left: 0px; width: 100%;')

link(rel="stylesheet", href=url_for("/css/biliBg/spring/spring.css"))
script(src=url_for("/js/biliBg/spring/spring.js") data-pjax)

winter.pug

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.bldbanner
.bldview
img.morning(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/winter/bilibili-winter-view-1.webp')
img.afternoon(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/winter/bilibili-winter-view-2.webp')
img.ball(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/winter/bilibili-winter-ball.png')
video.evening(autoplay, loop, muted)
source(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/winter/bilibili-winter-view-3.webm', type='video/webm')
img.window-cover(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/winter/bilibili-winter-view-3-snow.png')
.tree
img.morning(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/winter/bilibili-winter-tree-1.png')
img.afternoon(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/winter/bilibili-winter-tree-2.png')
img.evening(src='https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/winter/bilibili-winter-tree-3.png')

link(rel="stylesheet", href=url_for("/css/biliBg/winter/winter.css"))
script(src=url_for("/js/biliBg/winter/winter.js"))

然后发现 pug 居然不能动态引入组件化,因为在编译的时候就已经确定 html 结构了,然而我还是在已经上线后才知道,还曾一度怀疑是 cdn 的缓存 🤡。

最后修改改改还是磕磕绊绊的完成了春秋冬的集成,就是这 js 代码我真的觉得好难受。

魔改记录

判断文章是否需要随机 banner

修改 themes/butterfly/layout/includes/header/index.pug,引入我们的 bili-banner,首先判断文章顶部是否有 bilibili_bg,如果有就引入 bilibili 随机 banner

1
2
3
4
5
6
7
header#page-header(class=`${isHomeClass}`)
!=partial('includes/header/nav', {}, {cache: true})
if top_img !== false
if is_post()
include ./post-info.pug
+ if page.bilibili_bg
+ !=partial('includes/bili-banner/index')

新建 themes/butterfly/layout/includes/bili-banner/index.pug,这段直接引入所需要的 js

1
2
//- 随机背景
script(src=url_for("/js/biliBg/biliBg.js"), data-pjax)

新建source/js/biliBg/biliBg.js, 动态插入节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
var biliBannerIndex = Math.floor(Math.random() * 3);
var $biliBannerParentsEl = document.getElementById("page-header");
//- 创建脚本节点
var biliBannerScript = document.createElement("script");
biliBannerScript.type = "text/javascript";
console.info(biliBannerIndex);
if (biliBannerIndex === 0) {
//- autumn
$biliBannerParentsEl.insertAdjacentHTML(
"beforeend",
`
<div class="blqbanner mobile-hidden">
<div><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/autumn/bilibili-autumn-1.webp"/></div>
<div><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/autumn/bilibili-autumn-2.png"/></div>
<div><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/autumn/bilibili-autumn-3.png"/></div>
<div><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/autumn/bilibili-autumn-4.png"/></div>
<div><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/autumn/bilibili-autumn-5.png"/></div>
<div><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/autumn/bilibili-autumn-6.png"/></div>
</div>
<link rel="stylesheet", href="/css/biliBg/autumn/autumn.css" />
`
);

//- 插入js节点
biliBannerScript.src = "https://npm.elemecdn.com/anzhiyu-blog@2.1.7/js/biliBg/autumn/autumn.js";
$biliBannerParentsEl.appendChild(biliBannerScript);
} else if (biliBannerIndex === 1) {
//- spring
$biliBannerParentsEl.insertAdjacentHTML(
"beforeend",
`
<div class="bili-banner">
<div class="animated-banner">
<div class="layer"><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/bg1.png" data-height="360" data-width="9666" height="180" width="4833" style="transform: scale(1) translate(0px, -15px) rotate(0deg); opacity: 1;"/></div>
<div class="layer"><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/bg2.png" data-height="360" data-width="9666" height="180" width="4833" style="transform: scale(1) translate(1100px, 0px) rotate(0deg); opacity: 1;"/></div>
<div class="layer"><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/bg3.png" data-height="360" data-width="3523" height="162" width="1585" style="transform: scale(1) translate(675px, 0px) rotate(0deg); opacity: 1;"/></div>
<div class="layer"><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/bg4.png" data-height="360" data-width="2938" height="176" width="1439" style="transform: scale(1) translate(-637px, 0px) rotate(0deg); opacity: 1;"/></div>
<div class="layer"><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/bg5.png" data-height="139" data-width="556" height="62" width="250" style="transform: scale(1) translate(607.5px, 45px) rotate(0deg); opacity: 1;"/></div>
<div class="layer"><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/p4.png" data-height="302" data-width="734" height="84" width="205" style="transform: scale(1) translate(252px, 36.4px) rotate(0deg); opacity: 0;"/></div>
<div class="layer"><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/bg6.png" data-height="180" data-width="1757" height="125" width="1229" style="transform: scale(1) translate(112px, 25px) rotate(0deg); opacity: 1;"/></div>
<div class="layer"><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/bg7.png" data-height="116" data-width="1757" height="81" width="1229" style="transform: scale(1) translate(-350px, 49px) rotate(0deg); opacity: 1;"/></div>
<div class="layer"><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/p2.png" data-height="346" data-width="497" height="138" width="198" style="transform: scale(1) translate(-240px, 16px) rotate(0deg); opacity: 0;"/></div>
<div class="layer"><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/p1.png" data-height="256" data-width="146" height="102" width="58" style="transform: scale(1) translate(-340px, 32px) rotate(0deg); opacity: 0;"/></div>
<div class="layer"><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/t1.png" data-height="254" data-width="602" height="114" width="270" style="transform: scale(1) translate(-90px, 13.5px) rotate(0deg); opacity: 1;"/></div>
<div class="layer"><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/bg8.png" data-height="360" data-width="4277" height="180" width="2138" style="transform: scale(1) translate(100px, 0px) rotate(0deg); opacity: 1;"/></div>
<div class="layer"><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/p3.png" data-height="327" data-width="933" height="147" width="419" style="transform: scale(1) translate(216px, 13.5px) rotate(0deg); opacity: 1;"/></div>
<div class="layer"><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/t3.png" data-height="353" data-width="740" height="211" width="444" style="transform: scale(1) translate(2100px, 0px) rotate(0deg); filter: blur(2px); opacity: 1;"/></div>
<div class="layer"><img src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/spring/t2.png" data-height="360" data-width="1916" height="180" width="958" style="transform: scale(1) translate(-1000px, 0px) rotate(0deg); filter: blur(1px); opacity: 1;"/></div>
<canvas id="springCanvas" width="1519" height="155" style="position: absolute; top: 0px; left: 0px;width: 100%;"></canvas>
</div>
</div>
<link rel="stylesheet", href="/css/biliBg/spring/spring.css" />
`
);

//- 插入js节点
biliBannerScript.src = "https://npm.elemecdn.com/anzhiyu-blog@2.1.7/js/biliBg/spring/spring.js";
$biliBannerParentsEl.appendChild(biliBannerScript);
} else if (biliBannerIndex === 2) {
//- winter
$biliBannerParentsEl.insertAdjacentHTML(
"beforeend",
`
<div class="bldbanner">
<div class="bldview"><img class="morning" src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/winter/bilibili-winter-view-1.webp"/><img class="afternoon" src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/winter/bilibili-winter-view-2.webp"/><img class="ball" src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/winter/bilibili-winter-ball.png"/>
<video class="evening" autoplay="autoplay" loop="loop" muted="muted">
<source src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/winter/bilibili-winter-view-3.webm" type="video/webm"/>
</video><img class="window-cover" src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/winter/bilibili-winter-view-3-snow.png"/>
</div>
<div class="tree"><img class="morning" src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/winter/bilibili-winter-tree-1.png"/><img class="afternoon" src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/winter/bilibili-winter-tree-2.png"/><img class="evening" src="https://npm.elemecdn.com/anzhiyu-blog@2.1.7/img/banner/winter/bilibili-winter-tree-3.png"/></div>
</div>
<link rel="stylesheet", href="/css/biliBg/winter/winter.css" />
`
);

//- 插入js节点
biliBannerScript.src = "https://npm.elemecdn.com/anzhiyu-blog@2.1.7/js/biliBg/winter/winter.js";
$biliBannerParentsEl.appendChild(biliBannerScript);
}

部分适配 css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.post-bg:has(.bldbanner) #post-info:after,
.post-bg:has(.bili-banner) #post-info:after,
.post-bg:has(.blqbanner) #post-info:after {
box-shadow: 0px -214px 287px 45px var(--anzhiyu-black-op) inset;
}
.post-bg:has(.bldbanner) #post-info .post-meta,
.post-bg:has(.bili-banner) #post-info .post-meta,
.post-bg:has(.blqbanner) #post-info .post-meta {
pointer-events: all;
}
.post-bg:has(.bldbanner) #post-info,
.post-bg:has(.bili-banner) #post-info,
.post-bg:has(.blqbanner) #post-info {
pointer-events: none;
}
#page-header.post-bg:has(.bldbanner),
#page-header.post-bg:has(.bili-banner),
#page-header.post-bg:has(.blqbanner) {
height: 15rem;
}

春 spring.css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
.bili-banner {
margin: 0 auto;
position: relative;
z-index: 0;
width: 100%;
height: 11rem;
min-height: 155px;
min-width: 999px;
background-color: #f9f9f9;
display: flex;
justify-content: center;
margin-top: 60px;
}
.bili-banner .animated-banner {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
overflow: hidden;
}

.bili-banner .layer {
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}

.bili-banner .layer img {
transition: transform 0.2s;
}

秋 autumn.css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
.blqbanner {
height: 15rem;
position: relative;
overflow: hidden;
}

.blqbanner > div {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
/* 将图片上下左右居中*/
display: flex;
justify-content: center;
align-items: center;
--offset: 0px;
--blur: 2px;
}

.blqbanner > div > img {
display: flex;
width: 110%;
/* 图片需要左右移动,预先设置的宽一些*/
height: 100%;
object-fit: cover;
/* 将图片按照比例填满容器*/
transform: translateX(var(--offset));
filter: blur(var(--blur));
transition: 0.3s;
}
.blqbanner > div:nth-child(1) > img {
--offset: 1.38426px;
--blur: 0.226766px;
}
.blqbanner > div:nth-child(2) > img {
--offset: 1.79954px;
--blur: 0.0724451px;
}
.blqbanner > div:nth-child(3) > img {
--offset: 2.3394px;
--blur: 1.02924px;
}
.blqbanner > div:nth-child(4) > img {
--offset: 3.04122px;
--blur: 3.09714px;
}
.blqbanner > div:nth-child(5) > img {
--offset: 3.95358px;
--blur: 6.27615px;
}
.blqbanner > div:nth-child(6) > img {
--offset: 5.13966px;
--blur: 10.5663px;
}

冬 winter.css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
.bldbanner {
min-height: 155px;
height: 20rem;
position: relative;
overflow: hidden;
--percentage: 0.5;
}

.bldbanner .tree,
.bldbanner .bldview {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-transition: all 0.2s ease-in;
transition: all 0.2s ease-in;
}

.bldbanner .bldview {
-webkit-transform: translatex(calc(var(--percentage) * 100px));
transform: translatex(calc(var(--percentage) * 100px));
}

.bldbanner .tree {
-webkit-transform: translatex(calc(var(--percentage) * 150px - 25px));
transform: translatex(calc(var(--percentage) * 150px - 25px));
-webkit-filter: blur(3px);
filter: blur(3px);
}

.bldbanner img,
.bldbanner video {
position: absolute;
height: 100%;
max-width: none;
}

.bldbanner .evening {
-webkit-transition: all 0.2s ease-in;
transition: all 0.2s ease-in;
z-index: 20;
opacity: calc((0.5 - var(--percentage)) / 0.5);
}

.bldbanner .afternoon {
-webkit-transition: all 0.2s ease-in;
transition: all 0.2s ease-in;
z-index: 10;
opacity: calc(1 - (var(--percentage) - 0.5) / 0.5);
}

.bldbanner.moving .afternoon,
.bldbanner.moving .ball,
.bldbanner.moving .evening,
.bldbanner.moving .tree,
.bldbanner.moving .bldview {
-webkit-transition: none;
transition: none;
}

.bldbanner .ball {
-webkit-transition: all 0.2s ease-in;
transition: all 0.2s ease-in;
z-index: 10;
opacity: calc(1.5 - (var(--percentage) - 0.5) / 0.5);
-webkit-transform: translate(calc(100px * var(--percentage)), 22px) rotate(calc(10deg * var(--percentage) + 5deg));
transform: translate(calc(100px * var(--percentage)), 22px) rotate(calc(10deg * var(--percentage) + 5deg));
}

.bldbanner .window-cover {
z-index: 20;
opacity: calc(var(--percentage) * -2);
}

总结

总的来说还不错,巩固了我对于 canvas 的知识与 css 视差绘制。