Note

Hexo NexT 主题添加雪花飘落的效果

2023-03-24 #Hexo

主题的模板改成 NexT.Pisces 后,背景看着有些单调,就想加点特效。

搜索一番,发现现在 NexT 主题可以很方便的引入自定义内容了,不需要修改主题的源文件,方便多了。
通过咨询 ChatGPT ,加上了雪花飘落的效果。

下面是具体的添加方法。

Hexo v5.4.2
NexT v8.15.0
适用于深色主题

修改主题设置

使用了 Javascript 和 CSS 来实现效果

在 NexT 主题的 _config.yaml 中,找到 custom_file_path ,取消对应的注释

_config.yaml
1
2
3
4
5
custom_file_path:
# 存放自定义 CSS 样式
style: source/_data/styles.styl
# 存放在 <body> 末尾加载的内容
bodyEnd: source/_data/body-end.njk

然后在 Hexo 目录下的 source 文件夹,创建 _data 文件夹
再创建 styles.stylbody-end.njk 文件

添加实现代码

添加 JS 代码

body-end.njk 中加入 JS 代码

  • 雪花随机大小
  • 有三种样式
  • 落到底部会停留一段时间

将动画交给 CSS 处理,不过动态效果还是使用 JS 处理动画的表现更好
预览

source/_data/body-end.njk
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
<script>
const snowflakes = ["⛄", "❄", "❄", "❆", "❅", "✥"];
// 创建雪花
function createSnowflake() {
const snowflake = document.createElement("span");
snowflake.classList.add("snowflake");
const randomIndex = Math.floor(Math.random() * snowflakes.length);
snowflake.textContent = snowflakes[randomIndex];

// 起始位置
/* 80%概率 生成在页面两侧 30% 的位置
const probability = Math.random();
let startPosition = Math.random() * 100;

if (probability < 0.8) {
startPosition = Math.random() < 0.5 ? Math.random() * 30 : (Math.random() * 30) + 70;
}
snowflake.style.left = `${startPosition}vw`;
*/
snowflake.style.left = `${Math.random() * 100}vw`;
snowflake.style.top = `-30px`;
// 雪花大小与透明度
const size = Math.random() * 18 + 10;
snowflake.style.fontSize = `${size}px`;
const opacity = Math.random() * 0.6 + (size > 18 ? 0.4 : 0);
snowflake.style.setProperty("--opacity", opacity);
// 动画持续时间
const fallDuration = Math.random() * 10 + 10;
// 旋转持续时间
const rotateDuration = Math.random() * 3 + 1;

snowflake.style.animationDuration = `${fallDuration}s, ${fallDuration}s`; // 向 CSS 添加淡出动画的持续时间
// 横向幅度
const translateX = (Math.random() * 500 - 200);
snowflake.style.setProperty("--translateX", `${translateX}px`);
// 纵向幅度
snowflake.style.setProperty("--translateY", `${window.innerHeight}px`);

document.body.appendChild(snowflake);
// 移除雪花
setTimeout(() => {
snowflake.remove();
}, fallDuration * 1000);
}

function snowfallAnimation() {
// 载入时若边栏是隐藏状态则不加载雪花
const sidebarnav = document.querySelector('.sidebar');
const sidebarnavdisplay = window.getComputedStyle(sidebarnav).getPropertyValue('display');
if (sidebarnavdisplay !== 'none') {
createSnowflake();
}
setTimeout(snowfallAnimation, 150); // 生成速度,毫秒
}
snowfallAnimation();
</script>

添加样式

styles.styl 文件中加入雪花样式代码,

  • 设置颜色
  • 置于网页底部层级
  • 鼠标无法选择
  • 加入一点荧光
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
/* 雪花 */
.snowflake {
position: fixed;
pointer-events: none;
animation-name: snowflakeFallRotate, snowflakeFadeOut;
animation-timing-function: linear;
animation-iteration-count: 1;
animation-fill-mode: forwards;
color: white;
pointer-events: none;
z-index: -1;
text-shadow: 0 0 1px rgba(255, 255, 255, 0.8), 0 0 5px rgba(255, 255, 255, 0.8);
}

@keyframes snowflakeFallRotate {
0% {
transform: translateY(0) translateX(0) rotate(0);
}
/* 下落到底部所用时间 */
70% {
transform: translateY(var(--translateY)) translateX(var(--translateX)) rotate(720deg);
}
100% {
transform: translateY(var(--translateY)) translateX(var(--translateX)) rotate(800deg);
}
}

@keyframes snowflakeFadeOut {
0%, 90% {
opacity: var(--opacity);
}
100% {
opacity: 0;
}
}
/* 雪花 END */

此时可以 hexo g && hexo s 预览了。

不过这时可以看到由于 NexT.Pisces 边栏和文章主体部分没有透明效果,效果并不好。

我们可以在 styles.styl 中加入下面内容,加上一点透明效果。

source/_data/styles.styl
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
/* 设置透明 */
.sidebar {
opacity: 0.85;
}
.header, .main-inner {
background-color: rgba(255,255,255,0.8);
}
.menu-item a:hover, .menu-item a.menu-item-active {
background-color: rgba(150,150,150,0.1);
}
.site-brand-container {
background-color: rgba(0,0,0,0.75);
}

/* For DarkMode */
if (hexo-config('darkmode')) {
@media (prefers-color-scheme: dark){
/* 侧栏、主体添加透明 */
.sidebar {
opacity: 0.8;
}
.header, .main-inner {
background-color: rgba(39,39,39,0.75);
}
.site-brand-container {
background-color: rgba(0,0,0,0.5);
}
}
}

本地预览没有问题,既可以推送到服务端了。

:2233_卖萌:

限制在顶部 30%

看了几天,确实花里胡哨 😅 ,只在顶部有一点效果就不错

修改 JS

source/_data/body-end.njk
1
2
3
4
5
// 缩短动画持续时间
const fallDuration = Math.random() * 10 + 5;

// 限制纵向幅度
snowflake.style.setProperty("--translateY", `${window.innerHeight * 0.3}px`);

修改样式文件动画的部分

source/_data/styles.styl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@keyframes snowflakeFallRotate {
0% {
transform: translateY(0) translateX(0) rotate(0);
}
/* 下落到底部所用时间 */
100% {
transform: translateY(var(--translateY)) translateX(var(--translateX)) rotate(800deg);
}
}

@keyframes snowflakeFadeOut {
0%, 50% {
opacity: var(--opacity);
}
100% {
opacity: 0;
}
}
评论
分享

评论