前言

记录一下自己折腾hexo-butterfly主题的记录,方便以后查阅
2025.06.26更新:

  • 此文不再更新,修改后的主题已同步至theme分支,不定时更新
  • 修改了默认的loading动画,增加了Hitokoto文本
  • 增加动态标题

    参考Heo同款loading动画
    增加了Hitokoto文本

正文

修改loading动画

1.修改/themes/butterfly/source/css/_layout/loading.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
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
if hexo-config('preloader')
.loading-bg
display: flex;
width: 100%;
height: 100%;
position: fixed;
background: linear-gradient(-135deg, #E2B0FF 10%, #f295c7 30%, #4e9ce4 90%, #23d5ab 100%);
z-index: 1001;
opacity: 1;
transition: .3s;
background-size: 400% 400%;
animation: backgroundglow 8s ease-in-out infinite;

#loading-box
.loading-img
width: 100px;
height: 100px;
border-radius: 50%;
margin: auto;
border: 4px solid #f0f0f2;
animation-duration: .3s;
animation-name: loadingAction;
animation-iteration-count: infinite;
animation-direction: alternate;
.loading-image-dot
width: 30px;
height: 30px;
background: linear-gradient(135deg, #E2B0FF 10%, #f295c7 50%, #4e9ce4 90%, #23d5ab 100%);
position: absolute;
border-radius: 50%;
border: 6px solid #fff;
top: 50%;
left: 50%;
transform: translate(18px, 24px);
&.loaded
.loading-bg
opacity: 0;
z-index: -1000;

#hitokoto-text
position: absolute
top: 68%
left: 50%
transform: translate(-50%, -50%)
width: 80%
max-width: 600px
padding: 10px
font-size: 24px
color: #fff
text-align: center
background: rgba(0, 0, 0, 0)
border-radius: 8px
z-index: 1002
animation: fadeIn 1s ease-in-out

@keyframes loadingAction
0% {
opacity: 1;
}
100% {
opacity: .4;
}

@keyframes backgroundglow
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}

@keyframes fadeIn
0% {
opacity: 0;
}
100% {
opacity: 1;
}

2.修改/themes/butterfly/layout/includes/loading/fullpage-loading.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
#loading-box(onclick='this.classList.add("loaded")')
.loading-bg
.loading-img
.loading-image-dot
#hitokoto-text

script.
(()=>{
function getHitokoto() {
const hitokotoEl = document.getElementById('hitokoto-text');
if (!hitokotoEl) return;
fetch('https://v1.hitokoto.cn')
.then(response => response.json())
.then(data => {
hitokotoEl.innerText = data.hitokoto;
})
.catch(() => {
hitokotoEl.innerText = '🐱喵喵喵🐱';
})
}
const $loadingBox = document.getElementById('loading-box')
const $body = document.body
const preloader = {
endLoading: () => {
$body.style.overflow = ''
$loadingBox.classList.add('loaded')
},
initLoading: () => {
$body.style.overflow = 'hidden'
$loadingBox.classList.remove('loaded')
getHitokoto()
}
}

preloader.initLoading()
window.addEventListener('load', preloader.endLoading)

if (!{theme.pjax && theme.pjax.enable}) {
btf.addGlobalFn('pjaxSend', preloader.initLoading, 'preloader_init')
btf.addGlobalFn('pjaxComplete', preloader.endLoading, 'preloader_end')
}
})()

3.修改/themes/butterfly/layout/includes/loading/index.pug

1
2
3
4
5
6
7
8
if theme.preloader.enable
if theme.preloader.source === 1
include ./fullpage-loading.pug
else if theme.preloader.source === 2
include ./pace.pug
else
include ./fullpage-loading.pug
include ./pace.pug

4.新建/source/css/loading_bar.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
.pace {
-webkit-pointer-events: none;
pointer-events: none;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
z-index: 2000;
position: fixed;
margin: auto;
top: 18px;
left: 0;
right: 0;
height: 8px;
border-radius: 8px;
width: 10rem;
background: rgba(255, 255, 255, 0.2);
border: 1px #e3e8f7;
overflow: hidden;
}

.pace-inactive .pace-progress {
opacity: 0;
transition: 0.3s ease-in;
}

.pace .pace-progress {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
-o-box-sizing: border-box;
box-sizing: border-box;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
max-width: 200px;
position: absolute;
z-index: 2000;
display: block;
top: 0;
right: 100%;
height: 100%;
width: 100%;
background: linear-gradient(90deg, #E2B0FF 0%, #f295c7 40%, #4e9ce4 70%, #23d5ab 100%);
animation: gradient 1.5s ease infinite;
background-size: 200%;
box-shadow: 0 0 10px rgba(126, 87, 194, 0.5), 0 0 20px rgba(126, 87, 194, 0.5);
}

.pace.pace-inactive {
opacity: 0;
transition: 0.3s;
top: -30px;
}

@keyframes gradient {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}

5.新建/source/css/loading_img.css

1
2
3
4
.loading-img {
background: url(你的头像地址) no-repeat center center;
background-size: cover;
}

6.新建/source/js/hotokoto.js

1
2
3
4
5
6
7
8
9
10
11
12
13
document.addEventListener("DOMContentLoaded", () => {
const hitokotoEl = document.getElementById('hitokoto-text');
if (!hitokotoEl) return;

fetch('https://v1.hitokoto.cn/')
.then(response => response.json())
.then(data => {
hitokotoEl.textContent = data.hitokoto;
})
.catch(() => {
hitokotoEl.textContent = '喵喵喵~';
});
});

7.修改_config.butterfly.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Loading Animation
preloader:
enable: true
# source
# 1. fullpage-loading
# 2. pace (progress bar)
source: 3 # 改为3,同时加载fullpage-loading和pace
# pace theme (see https://codebyzach.github.io/pace/)
pace_css_url: /css/loading_bar.css

...

# Inject
# Insert the code to head (before '</head>' tag) and the bottom (before '</body>' tag)
inject:
head:
# - <link rel="stylesheet" href="/xxx.css">
- <link rel="stylesheet" href="/css/loading_img.css">
bottom:
# - <script src="xxxx"></script>
- <script src="/js/hitokoto.js"></script>

添加动态标题

1.新建/source/js/dynamic_title.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
document.addEventListener("DOMContentLoaded", () => {
const leave = '离开页面时的标题';
const back = '返回页面时的标题';
const defaultTitle = document.title;
document.addEventListener('visibilitychange', function() {
if (document.visibilityState === 'hidden') {
document.title = leave;
clearTimeout(titleTime);
} else {
document.title = back;
titleTime = setTimeout(() => {
document.title = originTitle;
}, 5000);
}
});
})

此js文件的作用是,当用户离开页面时,标题会变成“离开页面时的标题”,当用户返回页面时,标题会变成“返回页面时的标题”,并在5秒后恢复为原来的标题

2.修改_config.butterfly.yml

1
2
3
4
5
6
7
8
9
10
# Inject
# Insert the code to head (before '</head>' tag) and the bottom (before '</body>' tag)
inject:
head:
# - <link rel="stylesheet" href="/xxx.css">
- <link rel="stylesheet" href="/css/loading_img.css">
bottom:
# - <script src="xxxx"></script>
- <script src="/js/hitokoto.js"></script>
- <script src="/js/dynamic_title.js"></script>

测试

1
hexo cl && hexo g && hexo s

loading效果

效果