前言

Butterfly自带的404页面比较简陋,就是一张图片加个”404”大字。这里用Glitch(故障风)效果重新设计,纯CSS动画实现,不依赖任何图片资源。

美化之前

需要修改网站的源文件、添加样式,需要一点基础,可以参考:

前提

确保_config.butterfly.ymlerror_404.enable设置为true

效果

修改方案

1. 修改404.pug

修改[blogRoot]/themes/butterfly/layout/includes/404.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
- var top_img_404 = theme.error_404.background || theme.default_top_img

#body-wrap.error404
include ./header/index.pug

.error-decor
.decor-circle.d1
.decor-circle.d2
.decor-circle.d3
.decor-cross.x1 +
.decor-cross.x2 +
.decor-cross.x3 +
.decor-dot.dot1
.decor-dot.dot2
.decor-dot.dot3
.decor-dot.dot4
.decor-dot.dot5

#error-wrap
.error-content
.error-illustration
.glitch-wrap
.glitch(data-text="404") 404
p.lost-text 页面去哪了?
.error-divider
.error-info
p.error_subtitle= theme.error_404.subtitle || '抱歉,你访问的页面不存在'
p.error_desc 可能是链接过期了,或者地址输入有误
.error_buttons
a.error_btn(href="/")
i.fas.fa-home
span 回到首页
a.error_btn(href="javascript:window.history.back();")
i.fas.fa-undo
span 返回上页
a.error_btn(href="javascript:toRandomPost()")
i.fas.fa-random
span 随便看看
说明

toRandomPost()是随机跳转文章的函数,如果你没有定义可以去掉最后一个按钮

2. 修改404.styl

修改[blogRoot]/themes/butterfly/source/css/_page/404.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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
if hexo-config('error_404.enable')
.error404
// 背景装饰
&::before
content: ''
position: fixed
top: 0
left: 0
width: 100%
height: 100%
background: radial-gradient(ellipse at 15% 30%, rgba(230,130,130,0.12) 0%, transparent 45%), radial-gradient(ellipse at 85% 70%, rgba(230,130,130,0.1) 0%, transparent 40%), radial-gradient(ellipse at 50% 90%, rgba(230,160,130,0.08) 0%, transparent 35%)
pointer-events: none
z-index: 0

[data-theme="dark"] &
background: radial-gradient(ellipse at 15% 30%, rgba(242,185,75,0.06) 0%, transparent 45%), radial-gradient(ellipse at 85% 70%, rgba(242,185,75,0.05) 0%, transparent 40%), radial-gradient(ellipse at 50% 90%, rgba(242,185,75,0.04) 0%, transparent 35%)

// 浮动几何装饰
&::after
content: ''
position: fixed
top: 10%
right: 8%
width: 250px
height: 250px
border: 2px dashed rgba(230,130,130,0.2)
border-radius: 50%
animation: spin404 20s linear infinite
pointer-events: none
z-index: 0

[data-theme="dark"] &
border-color: rgba(242,185,75,0.12)

#error-wrap
position: absolute
top: 50%
right: 0
left: 0
margin: 0 auto
padding: 0 20px
max-width: 800px
transform: translateY(-50%)
z-index: 1

.error-content
display: flex
flex-direction: column
align-items: center
text-align: center

.error-illustration
margin-bottom: 30px

.glitch-wrap
position: relative
display: inline-block

.glitch
font-size: 12em
font-weight: 900
line-height: 1
color: var(--june-theme)
position: relative
letter-spacing: -5px
animation: glitchShift 5s infinite

+maxWidth768()
font-size: 8em

&::before
&::after
content: attr(data-text)
position: absolute
top: 0
left: 0
width: 100%
height: 100%

&::before
color: var(--june-theme)
opacity: 0.8
animation: glitchTop 2s infinite
clip-path: polygon(0 0, 100% 0, 100% 40%, 0 40%)
-webkit-clip-path: polygon(0 0, 100% 0, 100% 40%, 0 40%)

&::after
color: var(--june-theme)
opacity: 0.6
animation: glitchBottom 1.8s infinite
clip-path: polygon(0 60%, 100% 60%, 100% 100%, 0 100%)
-webkit-clip-path: polygon(0 60%, 100% 60%, 100% 100%, 0 100%)

.lost-text
font-size: 1.2em
color: #b2bec3
margin-top: 5px
letter-spacing: 8px
text-transform: uppercase

.error-divider
width: 50px
height: 3px
background: var(--june-theme)
border-radius: 2px
margin: 25px 0
opacity: 0.6

.error-info
.error_subtitle
font-size: 1.3em
color: var(--font-color)
font-weight: 600
margin: 0 0 8px

.error_desc
font-size: 0.95em
color: #999
margin: 0 0 30px

.error_buttons
display: flex
gap: 12px
flex-wrap: wrap
justify-content: center

.error_btn
display: inline-flex
align-items: center
gap: 4px
padding: 10px 22px
border-radius: 8px
font-size: 0.88em
text-decoration: none
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1)
font-weight: 500
background: var(--june-card-bg, #fff)
color: var(--font-color)
border: 1px solid var(--june-card-border, #e8e8e8)

&:hover
transform: translateY(-2px)
border-color: var(--june-theme)
color: var(--june-theme)
box-shadow: 0 4px 12px rgba(230,130,130,0.15)

& + #rightside
display: none

// 装饰元素
.error404 .error-decor
position: fixed
top: 0
left: 0
width: 100%
height: 100%
pointer-events: none
z-index: 0
overflow: hidden

.decor-circle
position: absolute
border-radius: 50%
border: 2px solid rgba(230,130,130,0.15)

&.d1
width: 350px
height: 350px
top: -100px
left: -100px
border-width: 3px
border-color: rgba(230,130,130,0.12)
animation: floatDecor 8s ease-in-out infinite

&.d2
width: 180px
height: 180px
bottom: 8%
right: 3%
border-style: dashed
border-color: rgba(230,130,130,0.18)
animation: spin404 18s linear infinite

&.d3
width: 100px
height: 100px
top: 25%
left: 6%
background: rgba(230,130,130,0.08)
border: none
animation: floatDecor 6s ease-in-out infinite reverse

.decor-dot
position: absolute
border-radius: 50%
background: rgba(230,130,130,0.35)
animation: floatDot 4s ease-in-out infinite

&.dot1
top: 18%
left: 12%
width: 10px
height: 10px
animation-delay: 0s

&.dot2
top: 55%
left: 88%
animation-delay: 0.8s
width: 7px
height: 7px

&.dot3
top: 72%
left: 15%
animation-delay: 1.6s
width: 12px
height: 12px
opacity: 0.6

&.dot4
top: 12%
right: 18%
animation-delay: 2.4s
width: 8px
height: 8px

&.dot5
top: 40%
left: 92%
animation-delay: 3.2s
width: 6px
height: 6px

.decor-cross
position: absolute
font-size: 18px
color: rgba(230,130,130,0.25)
font-weight: 300
animation: floatDot 5s ease-in-out infinite

&.x1
top: 30%
right: 12%
animation-delay: 0.5s
font-size: 22px

&.x2
top: 65%
left: 10%
animation-delay: 1.5s
font-size: 16px

&.x3
bottom: 20%
right: 25%
animation-delay: 2.5s
font-size: 20px

// 暗色模式适配
[data-theme="dark"] .error404
.error-decor .decor-circle
border-color: rgba(242,185,75,0.12)

&.d3
background: rgba(242,185,75,0.06)

.error-decor .decor-dot
background: rgba(242,185,75,0.3)

.error-decor .decor-cross
color: rgba(242,185,75,0.2)

// 动画
@keyframes glitchTop
0%, 100%
transform: translate(0)
20%
transform: translate(-6px, -4px)
40%
transform: translate(6px, 4px)
60%
transform: translate(-4px, 2px)
80%
transform: translate(4px, -2px)

@keyframes glitchBottom
0%, 100%
transform: translate(0)
25%
transform: translate(5px, 3px)
50%
transform: translate(-4px, -2px)
75%
transform: translate(4px, 3px)

@keyframes glitchShift
0%, 85%, 100%
transform: translate(0)
87%
transform: translate(-4px, 2px)
89%
transform: translate(4px, -2px)
91%
transform: translate(-3px, -1px)
93%
transform: translate(3px, 1px)
95%
transform: translate(-2px, 3px)
97%
transform: translate(2px, -3px)

@keyframes spin404
from
transform: rotate(0deg)
to
transform: rotate(360deg)

@keyframes floatDecor
0%, 100%
transform: translateY(0)
50%
transform: translateY(-15px)

@keyframes floatDot
0%, 100%
transform: translateY(0) scale(1)
opacity: 0.3
50%
transform: translateY(-8px) scale(1.2)
opacity: 0.7

3. 确认配置

确保_config.butterfly.yml中404页面已启用:

1
2
3
error_404:
enable: true
subtitle: "页面没有找到"