方式一:使用代码(CSS / JS)

效果预览

浅色模式

深色模式

  • [blogroot]/source/文件夹下新建css文件夹,在css文件夹下新建文件o0w0b_cursor.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
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
/* 全局隐藏默认鼠标 */
* {
cursor: none !important;
}

/* 主题为浅色模式 */
html[data-theme="light"] {
--cursor-color: rgba(0, 0, 0, 1);
--cursor-background-color: rgba(0, 0, 0, 0.45);
--cursor-click-color: rgba(200, 200, 200, 0.4);
}

/* 主题为深色模式 */
html[data-theme="dark"] {
--cursor-color: rgba(255, 255, 255, 1);
--cursor-background-color: rgba(255, 255, 255, 0.5);
--cursor-click-color: rgba(200, 200, 200, 0.2);
}

#cursor {
position: fixed;
top: 0px;
left: 0px;
width: 32px;
height: 32px;
opacity: 0;
clip-path: polygon(50% 0%,
80% 70%,
50% 100%,
20% 70%);
background: var(--cursor-background-color);
backdrop-filter: blur(0.7px);
-webkit-backdrop-filter: blur(0.7px);
pointer-events: none;
transition:
width 0.15s ease,
height 0.15s ease,
border-color 0.15s ease,
box-shadow 0.15s ease;
will-change: transform;
z-index: 99999;
}

#cursor::after {
content: "";
position: absolute;
top: 5px;
/* 边框宽度 */
left: 5px;
right: 5px;
bottom: 5px;
background: var(--cursor-color);
/* 边框颜色 */
z-index: -1;
/* 比主元素稍大的相同形状 */
clip-path: polygon(50% 0%,
80% 70%,
50% 100%,
20% 70%);
}

/* 悬停元素时 */
#cursor.hover {
background: rgba(39, 157, 241, 0.7);
}

/* 鼠标点击动画 */
.CursorClick {
position: fixed;
width: 50px;
height: 50px;
border-radius: 50%;
pointer-events: none;
}

/* 外层波纹 */
.CursorClick::before,
.CursorClick::after {
content: '';
position: absolute;
width: 50px;
height: 50px;
border: 2px solid var(--cursor-click-color);
border-radius: 50%;
background: transparent;
transform: translate(-50%, -50%) scale(0);
animation: ripple 1s ease-out forwards;
}

/* 延迟让多层波纹连续扩散 */
.CursorClick::after {
animation-delay: 0.2s;
}

/* 波纹动画 */
@keyframes ripple {
0% {
transform: translate(-50%, -50%) scale(0);
opacity: 0.7;
}

50% {
transform: translate(-50%, -50%) scale(1);
opacity: 0.4;
}

100% {
transform: translate(-50%, -50%) scale(2);
opacity: 0;
}
}

/* 移动端禁用光标 */
@media (hover: none) {
#cursor {
display: none;
}
}
  • [blogroot]/source/文件夹下新建js文件夹,在js文件夹下新建文件o0w0b_cursor.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
// 创建光标
const cursor = document.createElement("div");
cursor.id = "cursor";

document.body.appendChild(cursor);

let mouseX = 0, mouseY = 0;

// 鼠标移动更新坐标
document.addEventListener("mousemove", (e) => {
cursor.style.opacity = "1";
mouseX = e.clientX;
mouseY = e.clientY;
// 与鼠标同步
cursor.style.transform = `translate3d(${mouseX}px, ${mouseY}px, 0) rotate(315deg)`;
});

/* 鼠标进入/离开屏幕内 */
window.addEventListener("mouseenter", () => {
cursor.style.opacity = "1";
});
window.addEventListener("mouseout", (e) => {
if (!e.relatedTarget && !e.toElement) {
cursor.style.opacity = "0";
}
});

/* 点击水波纹动画 */
document.addEventListener("click", () => {
const ripple = document.createElement("div");
ripple.className = "CursorClick";
ripple.style.left = `${mouseX}px`;
ripple.style.top = `${mouseY}px`;

// 保证光标在动画上层
document.body.insertBefore(ripple, cursor);

// 动画结束删除
ripple.addEventListener("animationend", () => ripple.remove());
});

/* 悬停状态交互 */
const hoverSelectors = `a, button, img, input, textarea, .copy-button, .code-expand-btn, .fullpage-button, .expand,
.scroll-down-effects, #footer-wrap, #pagination .page-number, #site-name, #nav .site-page,
.cursor-hover, .switch-btn, .switch-btn, .gt-user-inner, .gt-ico, .gt-user-name,
.gt-btn, .vbtn, svg, .at_button`;

document.addEventListener("mouseover", (e) => {
if (e.target.closest(hoverSelectors)) {
cursor.classList.add("hover");
} else {
cursor.classList.remove("hover");
}
});

/* false 禁用右键 */
document.oncontextmenu = () => false;
  • 引入新建的 css 和 js 文件,在主题的配置文件_config.butterfly.yml的 inject 中添加相应的内容
1
2
3
4
5
6
7
8
9
# Inject
# 插入代码到 head(在 '</head>' 标签之前)和底部(在 '</body>' 标签之前)
inject:
head:
# - <link rel="stylesheet" href="/xxx.css">
- <link rel="stylesheet" href="/css/o0w0b_cursor.css">
bottom:
# - <script src="xxxx"></script>
- <script src="/js/o0w0b_cursor.js"></script>

方式二:使用光标文件(.cur)

效果预览

默认样式

光标文件的像素大小推荐为 32 * 32

  • [blogroot]/source/文件夹下新建css文件夹,在css文件夹下新建文件PaperPlaneCursor.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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/* 全局默认鼠标指针 */
body,
html {
cursor: url('https://cdn.jsdelivr.net/gh/o0w0b/StaticFiles@main/cursors/PaperPlane_Cursor/01.cur'), auto !important;
}

/* 悬停图片时的鼠标指针 */
img {
cursor: url('https://cdn.jsdelivr.net/gh/o0w0b/StaticFiles@main/cursors/PaperPlane_Cursor/15.cur'), auto !important;
}

/* 悬停图片弹出窗口时的鼠标指针 */
.fancybox__slide {
cursor: url('https://cdn.jsdelivr.net/gh/o0w0b/StaticFiles@main/cursors/PaperPlane_Cursor/05.cur'), auto !important;
}

.carousel__slide {
cursor: url('https://cdn.jsdelivr.net/gh/o0w0b/StaticFiles@main/cursors/PaperPlane_Cursor/03.cur'), auto !important;
}

/* 选择链接标签时的鼠标指针 */
a:hover,
#site-name:hover {
cursor: url('https://cdn.jsdelivr.net/gh/o0w0b/StaticFiles@main/cursors/PaperPlane_Cursor/15.cur'), auto !important;
}

/* 选择代码复制按钮时的鼠标指针 */
.copy-button:hover {
cursor: url('https://cdn.jsdelivr.net/gh/o0w0b/StaticFiles@main/cursors/PaperPlane_Cursor/07.cur'), auto !important;
}

/* 选择代码全屏显示按钮时的鼠标指针 */
.fullpage-button {
cursor: url('https://cdn.jsdelivr.net/gh/o0w0b/StaticFiles@main/cursors/PaperPlane_Cursor/15.cur'), auto !important;
}

/* 选择代码框展开按钮时的鼠标指针 */
.expand:hover,
.code-expand-btn {
cursor: url('https://cdn.jsdelivr.net/gh/o0w0b/StaticFiles@main/cursors/PaperPlane_Cursor/15.cur'), auto !important;
}

/* 选中输入框时的鼠标指针 */
input:hover,
textarea:hover {
cursor: url('https://cdn.jsdelivr.net/gh/o0w0b/StaticFiles@main/cursors/PaperPlane_Cursor/06.cur'), auto;
}

/* 悬停按钮时的鼠标指针 */
button:hover,
.scroll-down-effects:hover {
cursor: url('https://cdn.jsdelivr.net/gh/o0w0b/StaticFiles@main/cursors/PaperPlane_Cursor/15.cur'), auto;
}

/* 悬停页脚链接标签(例如页脚徽标)时的鼠标指针 */
#footer-wrap a:hover {
cursor: url('https://cdn.jsdelivr.net/gh/o0w0b/StaticFiles@main/cursors/PaperPlane_Cursor/15.cur'), auto;
}

/* 悬停页码时的鼠标指针 */
#pagination .page-number:hover {
cursor: url('https://cdn.jsdelivr.net/gh/o0w0b/StaticFiles@main/cursors/PaperPlane_Cursor/15.cur'), auto;
}

/* 悬停菜单栏时的鼠标指针 */
#nav .site-page:hover {
cursor: url('https://cdn.jsdelivr.net/gh/o0w0b/StaticFiles@main/cursors/PaperPlane_Cursor/01.cur'), auto !important;
}

/* 悬停滚动条的鼠标指针(只对Chrome有效) */
::-webkit-scrollbar:hover {
cursor: url('https://cdn.jsdelivr.net/gh/o0w0b/StaticFiles@main/cursors/PaperPlane_Cursor/09.cur'), auto !important;
}

/* 悬停评论按钮的鼠标指针(我使用的是Gitalk/Valine) */
.switch-btn,
.switch-btn:before,
.gt-user-inner,
.gt-ico,
.gt-user-name,
.gt-btn,
.vbtn,
svg,
.at_button {
cursor: url('https://cdn.jsdelivr.net/gh/o0w0b/StaticFiles@main/cursors/PaperPlane_Cursor/15.cur'), auto !important;
}

/* 悬停非链接文本时的鼠标指针 */
h1,
h2,
h3,
h4,
h5,
h6,
#subtitle,
.content,
.line,
.post-content p,
.post-content li {
cursor: url('https://cdn.jsdelivr.net/gh/o0w0b/StaticFiles@main/cursors/PaperPlane_Cursor/06.cur'), auto;
}

/* 悬停文章日期 */
.post-meta-date:hover,
.post-meta-date-created:hover {
cursor: url('https://cdn.jsdelivr.net/gh/o0w0b/StaticFiles@main/cursors/PaperPlane_Cursor/06.cur'), auto !important;
}
  • 引入新建的 css 文件,在主题的配置文件_config.butterfly.yml的 inject 中添加相应的内容
1
2
3
4
5
6
# Inject
# 插入代码到 head(在 '</head>' 标签之前)和底部(在 '</body>' 标签之前)
inject:
head:
# - <link rel="stylesheet" href="/xxx.css">
- <link rel="stylesheet" href="/css/PaperPlaneCursor.css">