让 Hexo 安知鱼博客兼容 Obsidian 语法

让 Hexo 安知鱼博客兼容 Obsidian 语法

碎碎念

用 obsidian 黑曜石已经很多年,对它的语法已经非常习惯,然而安知鱼主题原生并不支持 obsidian 语法,而是自创了一套 tag plugin 标签语法,这就给我带来一个困扰:在 ob 里写文章使用安知鱼语法时,无法实现所见即所得的预览模式,且安知鱼标签语法众多,难以记忆,真的不想去记两套语法
于是,我开始对安知鱼的代码进行改造,使它兼容 ob 的原生语法,经过三四天的打磨,终于完成了最核心、最常用的部分

已实现的兼容语法

  • 提示块,ob 叫它 callout
  • ![图片1|600](a.webp) 的写法自定义图片尺寸
  • 链接卡片
  • 自动生成文章封面图(这不是 ob 语法,是本次折腾的附属产物)

一. 先看提示块

效果预览

  • 单行无标题

按图操作,注意端口一定不要错,格式 localhost:25002

  • 多行:默认标题 + 正文

信息

部署完成后等待两分钟,点击 CF 分配的域名访问博客

  • 多行:自定义标题 + 正文

特别建议

建议使用最新版本,旧版本可能存在兼容性问题

写法示例

关键词字段不区分大小写,此写法多行形式 obsidian 和 github 都支持

1
2
3
4
5
6
7
> [!TIP] 单行正文                        → 图标 + 同一行文字,无标题

> [!TIP] → 默认标题「提示」(加粗)
> 多行正文内容 → 正文

> [!TIP] 特别提示 → 标题「自定义标题」(加粗)
> 多行正文内容 → 正文

支持的字段与颜色

颜色 字段 色值
🔵 蓝 note, info, todo #027AFF
🌀 青 summary, tip, hint, important #53DFDD
🟢 绿 success, check, done #44CF6E
🟠 橙 help, faq, question, warning, caution #E9973F
🔴 红 fail, danger, error, bug #FB464C
🟣 紫 example, quote #A882FF

修改步骤

1. 创建 Hexo Filter

1
themes/anzhiyu/scripts/filters/blockquote.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
/**
* blockquote.js
* Auto-add FA icons to blockquotes with Obsidian/GitHub callout syntax
* Supports single-line and multi-line (title + body) layouts
* Color definitions are in source/css/article.css
*/

"use strict";

const typeMap = {
note: { icon: "fas fa-pencil", title: "备注" },
summary: { icon: "fas fa-clipboard-list", title: "摘要" },
info: { icon: "fas fa-info-circle", title: "信息" },
todo: { icon: "fas fa-check-circle", title: "待办" },
important: { icon: "fas fa-star", title: "重要" },
tip: { icon: "fas fa-fire", title: "提示" },
hint: { icon: "fas fa-fire", title: "提示" },
success: { icon: "fas fa-check-circle", title: "完成" },
check: { icon: "fas fa-check-circle", title: "检查" },
done: { icon: "fas fa-check-circle", title: "完成" },
help: { icon: "fas fa-circle-question", title: "帮助" },
faq: { icon: "fas fa-circle-question", title: "问题" },
question: { icon: "fas fa-circle-question", title: "疑问" },
warning: { icon: "fas fa-triangle-exclamation", title: "警告" },
caution: { icon: "fas fa-triangle-exclamation", title: "注意" },
danger: { icon: "fas fa-bolt", title: "危险" },
error: { icon: "fas fa-bolt", title: "错误" },
fail: { icon: "fas fa-xmark", title: "失败" },
bug: { icon: "fas fa-bug", title: "漏洞" },
example: { icon: "fas fa-flask", title: "示例" },
quote: { icon: "fas fa-quote-left", title: "引用" },
};

const keywords = Object.keys(typeMap).join("|");

// Match both single-line and multi-line callouts
// Supports <br> split (no blank line) and </p><p> split (blank line)
const regex = new RegExp(
`<blockquote>\\s*<p>\\s*\\[!\\s*(${keywords})\\s*\\](?:\\s+(.*?))?(?:<br>\\s*(.*?))?<\\/p>\\s*((?:<p>.*?<\\/p>)*)\\s*<\\/blockquote>`,
"gis"
);

hexo.extend.filter.register("after_post_render", (data) => {
if (!data.content) return;

data.content = data.content.replace(regex, (match, keyword, title, brBody, pBody) => {
const k = keyword.toLowerCase();
const type = typeMap[k];
if (!type) return match;

const bodyHtml = pBody || (brBody ? `<p>${brBody}</p>` : null);

if (bodyHtml) {
// Multi-line: title + body
const displayTitle = title && title.trim() ? title.trim() : type.title;
return `<blockquote class="bq-${k}"><i class="${type.icon} bq-icon"></i><p class="bq-title"><strong>${displayTitle}</strong></p>${bodyHtml}</blockquote>`;
}

// Single-line: icon + text on same line
return `<blockquote class="bq-${k}"><i class="${type.icon} bq-icon"></i><p>${title || ""}</p></blockquote>`;
});
});

2. 添加 CSS 样式

  • 文件路径
1
source/css/article.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
/* ===== 行内代码样式 ===== */
[data-theme="light"] #article-container code {
background-color: var(--anzhiyu-main-op) !important;
color: var(--anzhiyu-main) !important;
}

[data-theme="dark"] #article-container code {
background-color: rgba(242, 185, 75, 0.2) !important;
color: #f2b94b !important;
}

/* ===== Blockquote 默认样式 ===== */
blockquote {
border: none;
border-left: 4px solid var(--anzhiyu-lighttext);
}

[data-theme="light"] blockquote {
background-color: var(--anzhiyu-main-op);
}

[data-theme="dark"] blockquote {
background-color: rgba(242, 185, 75, 0.25);
}

/* ===== Blockquote 自动图标样式 ===== */
.bq-icon {
position: absolute;
left: 0.8em;
top: calc(50% - 0.5em);
font-size: larger;
}

blockquote:has(.bq-icon) {
position: relative;
padding-left: 3em;
}

/* 多行模式:图标对齐标题 */
blockquote:has(.bq-title) .bq-icon {
top: 0.82em;
font-size: 1.2em;
}

/* 标题样式 */
.bq-title {
font-weight: bold;
margin: 0 0 0 !important;
color: inherit;
}
.bq-title strong {
color: inherit;
}

/* 🔵 蓝 — note, info, todo */
.bq-note,
.bq-info,
.bq-todo { background-color: rgba(66,90,239,0.15) !important; border-left-color: #425AEF !important; color: #425AEF !important; }
.bq-note .bq-icon,
.bq-info .bq-icon,
.bq-todo .bq-icon { color: #425AEF; }

/* 🌀 青 — summary, tip, hint, important */
.bq-summary,
.bq-tip,
.bq-hint,
.bq-important { background-color: rgba(50, 200, 200,0.15) !important; border-left-color: #32c8c8 !important; color: #32c8c8 !important; }
.bq-summary .bq-icon,
.bq-tip .bq-icon,
.bq-hint .bq-icon,
.bq-important .bq-icon { color: #32c8c8; }

/* 🟢 绿 — success, check, done */
.bq-success,
.bq-check,
.bq-done { background-color: rgba(68,207,110,0.15) !important; border-left-color: #44CF6E !important; color: #44CF6E !important; }
.bq-success .bq-icon,
.bq-check .bq-icon,
.bq-done .bq-icon { color: #44CF6E; }

/* 🟠 橙 — help, faq, question, warning, caution */
.bq-help,
.bq-faq,
.bq-question,
.bq-warning,
.bq-caution { background-color: rgba(233,151,63,0.15) !important; border-left-color: #E9973F !important; color: #E9973F !important; }
.bq-help .bq-icon,
.bq-faq .bq-icon,
.bq-question .bq-icon,
.bq-warning .bq-icon,
.bq-caution .bq-icon { color: #E9973F; }

/* 🔴 红 — fail, danger, error, bug */
.bq-fail,
.bq-danger,
.bq-error,
.bq-bug { background-color: rgba(251,70,76,0.15) !important; border-left-color: #FB464C !important; color: #FB464C !important; }
.bq-fail .bq-icon,
.bq-danger .bq-icon,
.bq-error .bq-icon,
.bq-bug .bq-icon { color: #FB464C; }

/* 🟣 紫 — example, quote */
.bq-example,
.bq-quote { background-color: rgba(168,130,255,0.15) !important; border-left-color: #A882FF !important; color: #A882FF !important; }
.bq-example .bq-icon,
.bq-quote .bq-icon { color: #A882FF; }

3. 引用 CSS

  • _config.anzhiyu.ymlinject 配置中添加:
1
2
3
inject:
head:
- <link rel="stylesheet" href="/css/article.css">

二. 自定义图片尺寸

效果预览

  • 单行多图片
    图1 图2

  • 单行 1 张图片

图1

写法示例——obsidian 原生语法

1
2
3
4
5
6
7
8
9
10
- 单行多图写法,两个图片之间用1个空格分隔,图片总宽度加起来不要超过100%,否则会自动切换为两行
![图1|40%](https://aa.com/aa.webp) ![图2|40%](https://bb.com/bb.webp)
- 如果一行放三张图,可以写:
![图1|30%](aa.webp) ![图2|30%](bb.webp) ![图3|30%](cc.webp)

- 一行放一张图,但不满铺(安知鱼默认100%宽度满铺)
- 指定宽度,高度自适应
![图1|600](https://aa.com/aa.webp)
- 同时指定宽度和高度,注意,这里的 x 是小写的 X,不是*,也不是乘号,ob就是这么设计的
![图1|600x300](https://aa.com/aa.webp)

修改步骤

1. 创建 img-embed.js

  • 文件路径
1
themes/anzhiyu/scripts/filters/img-embed.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
/**
* img-embed.js
* Image dimension syntax compatible with Obsidian
* e.g. ![图片1|600](a.png) → <img src="a.png" alt="图片1" style="width:600px">
* e.g. ![图片1|42%](a.png) → <img src="a.png" alt="图片1" style="width:42%">
* e.g. ![图片1|600x280](a.png) → <img src="a.png" alt="图片1" style="width:600px;height:280px">
* e.g. ![600x360](a.png) → <img src="a.png" alt="" style="width:600px;height:360px">
* Note: Only images are supported. Audio/video not supported.
*/

"use strict";

// Pattern 1: alt="text|dim" — dimension in alt, any attribute order
const r1 = /<img\s+(?=[^>]*?src="([^"]+)")(?=[^>]*?alt="([^"]*?)\|(\d+(?:%|x\d+)?)")[^>]*\/?>/g;

// Pattern 2: alt="WxH" — entire alt is a dimension (no separator)
const r2 = /<img\s+(?=[^>]*?src="([^"]+)")(?=[^>]*?alt="(\d+)x(\d+)")[^>]*\/?>/g;

// Pattern 3: alt="number" — alt is a plain number (px width)
const r3 = /<img\s+(?=[^>]*?src="([^"]+)")(?=[^>]*?alt="(\d+)")[^>]*\/?>/g;

const buildStyle = (dim) => {
if (dim.includes("x")) {
const [w, h] = dim.split("x");
return `width:${w}px;height:${h}px`;
}
if (dim.includes("%")) return `width:${dim}`;
return `width:${dim}px`;
};

hexo.extend.filter.register("after_post_render", (data) => {
if (!data.content) return;

data.content = data.content.replace(r1, (_m, src, alt, dim) => `<img src="${src}" alt="${alt}" class="mediainline" style="${buildStyle(dim)}">`);
data.content = data.content.replace(r2, (_m, src, w, h) => `<img src="${src}" alt="" class="mediainline" style="width:${w}px;height:${h}px">`);
data.content = data.content.replace(r3, (_m, src, dim) => `<img src="${src}" alt="" class="mediainline" style="width:${dim}px">`);
});

2. 添加 CSS 样式

  • 文件路径
1
source/css/article.css
  • 在其中追加以下代码
1
2
3
4
5
6
7
8
9
10
11
/* 图片嵌入 — 父级居中 */
#article-container p:has(.mediainline) {
text-align: center;
}

/* 图片嵌入 — 改为 inline-block 实现并排 */
#article-container .mediainline {
display: inline-block;
vertical-align: middle;
margin-right: 10px;
}

千万记住

在主题里引用上述 CSS,引用方法上文已有,若已引用,则可忽略


链接卡片

需要重点说明一下

obsidian 原生并不支持自动生成链接卡片,但他有一个强大的插件 AutoCardLink Enhanced 可以生成非常精美的链接卡片,并支持明暗双模式

先看预览效果

写法示例

  • 其实不需要写语法,先在 ob 中安装 AutoCardLink Enhanced 插件
  • 复制需要外链的链接,到 ob 中点击右键,选择 Paste URL to a card link,即可自动生成

修改步骤

1. 创建 JS 文件

  • 文件路径
1
themes\anzhiyu\scripts\filters\link-card.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
/**
* link-card.js
* Render ```cardlink``` code blocks as rich cards (Obsidian plugin compat)
* Data comes from the cardlink block, no API calls needed.
*/

"use strict";

// Match cardlink blocks after Hexo syntax highlighting transforms them.
// Original: <pre><code class="language-cardlink">...</code></pre>
// After highlight: <figure class="highlight plaintext"><table>...<td class="code"><pre>lines...</pre></td>...</table></figure>
const CARD_BLOCK = /<figure class="highlight plaintext">[\s\S]*?<td class="code"><pre>([\s\S]*?)<\/pre>[\s\S]*?<\/figure>/gi;

// Decode HTML entities
const decodeHtml = (str) => {
return str
.replace(/&amp;/g, "&")
.replace(/&lt;/g, "<")
.replace(/&gt;/g, ">")
.replace(/&quot;/g, '"')
.replace(/&#x27;/g, "'")
.replace(/&#x2F;/g, "/");
};

const parseCardlink = (content) => {
const fields = {};
// Split by <br> to get individual lines, then strip HTML tags
const lines = content.split(/<br\s*\/?>/i);
lines.forEach((line) => {
const text = line.replace(/<[^>]+>/g, "").trim();
if (!text) return;
const m = text.match(/^\s*(\w+):\s*(?:"([^"]*)"|(.*))$/);
if (m) {
fields[m[1]] = decodeHtml((m[2] || m[3] || "").trim()).replace(/^"(.*)"$/, "$1");
}
});
return fields;
};

const renderCard = (fields) => {
const { url, title, description, host, favicon, image } = fields;
if (!url) return "";

const thumb = image
? `\n <div class="auto-card-link-thumbnail-wrap"><img class="auto-card-link-thumbnail" src="${image}" alt="" loading="lazy" draggable="false"></div>`
: "";
const desc = description
? `\n <div class="auto-card-link-description">${description}</div>`
: "";
const hostHtml = host
? `\n <div class="auto-card-link-host"><img class="auto-card-link-favicon" src="${favicon || ""}" alt="" loading="lazy"> <span>${host}</span></div>`
: "";

if (!title && !description) return "";

return `<div class="auto-card-link-container">
<a class="auto-card-link-card" href="${url}" target="_blank" rel="noopener">
${thumb}
<div class="auto-card-link-main">
<div class="auto-card-link-title">${title || url}</div>
${desc}
<div class="auto-card-link-meta">
${hostHtml}
<span class="auto-card-link-copy" onclick="navigator.clipboard.writeText('${url}')" title="复制链接"><i class="anzhiyufont anzhiyu-icon-link"></i></span>
</div>
</div>
</a>
</div>`;
};

hexo.extend.filter.register("after_post_render", (data) => {
if (!data.content) return;

data.content = data.content.replace(CARD_BLOCK, (_m, raw) => {
const fields = parseCardlink(raw);
return renderCard(fields);
});
});

2. 加入 CSS 样式

  • 文件路径——没错,还是这个文件
1
blog-demo\source\css\article.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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/* ===== Cardlink 卡片样式(Obsidian 插件兼容) ===== */
.auto-card-link-container {
margin-bottom: 24px;
}

.auto-card-link-card {
display: flex;
border: 1px solid var(--anzhiyu-card-border);
border-radius: 10px;
overflow: hidden;
text-decoration: none;
color: inherit;
background: var(--anzhiyu-secondbg);
transition: box-shadow 0.3s, transform 0.3s;
box-shadow: 4px 4px 12px rgba(0,0,0,0.1);
}
.auto-card-link-card:hover {
background: #E6E6ED;
box-shadow: 6px 6px 12px rgba(0,0,0,0.15);
transform: translateY(-3px);
}
[data-theme="dark"] .auto-card-link-card:hover {
background-color: #17191F;
}

.auto-card-link-main {
flex: 1;
padding: 12px 16px 12px 14px;
min-width: 0;
display: flex;
flex-direction: column;
justify-content: center;
}
.auto-card-link-title {
font-weight: bold;
font-size: 1rem;
color: var(--anzhiyu-main);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.auto-card-link-description {
color: var(--anzhiyu-fontcolor);
font-size: 0.85rem;
margin-top: 6px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
#article-container .auto-card-link-thumbnail.entered.loaded,
#article-container .auto-card-link-favicon.entered.loaded {
margin-bottom: 0;
}
.auto-card-link-host {
display: flex;
align-items: center;
gap: 6px;
font-size: 0.8rem;
color: var(--anzhiyu-lighttext);
}
.auto-card-link-favicon {
width: 18px;
height: 18px;
border-radius: 4px;
flex-shrink: 0;
}
.auto-card-link-thumbnail-wrap {
width: 260px;
min-width: 260px;
flex-shrink: 0;
overflow: hidden;
aspect-ratio: 16 / 9;
margin: 4px;
border-radius: 8px;
}
.auto-card-link-thumbnail {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}

.auto-card-link-meta {
margin-top: 6px;
display: flex;
align-items: center;
justify-content: space-between;
}
.auto-card-link-copy {
cursor: pointer;
color: var(--anzhiyu-lighttext);
font-size: 1rem;
transition: 0.2s;
flex-shrink: 0;
}
.auto-card-link-copy:hover {
color: var(--anzhiyu-main);
}

@media (max-width: 600px) {
.auto-card-link-card {
flex-wrap: wrap;
align-items: center;
}
.auto-card-link-main {
display: contents;
}
.auto-card-link-title {
order: 1;
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding: 10px;
margin: 0;
}
.auto-card-link-thumbnail-wrap {
order: 2;
width: 100px;
min-width: 100px;
aspect-ratio: 16 / 9;
margin: 8px;
}
.auto-card-link-description {
order: 3;
flex: 1;
min-width: 0;
-webkit-line-clamp: 3;
padding: 0 10px 0 0;
margin: 0;
}
.auto-card-link-meta {
order: 4;
width: 100%;
padding: 4px 10px 10px;
margin: 0;
}
}
  • 记住引用代码!

附加功能——自动生成封面图

注意

这个功能和 obsidian 没有任何关系,安知鱼原生也不支持,只是我为了偷懒,避免每次都去找封面图,很麻烦,才有了这个修改
效果就不看了,你点进我的博客,在首页看到的这篇文章的卡片,封面图就是自动生成的,包括图上的文字,他会自动提取文章标题放到图片上

前提条件

  • 要有一个随机图的 API,我可以提供一个 https://bing.by.ccwu.cc/api/daily?redirect=true,但不保证长期可用
  • 最好是可以自己部署一个,项目地址如下:
  • 在主题配置文件 config.anzhiyu.yml 中找到 default_cover: 字段,设置随机图直链 API 地址
1
2
3
cover:
default_cover:
- https://bing.by.ccwu.cc/daily.webp?redirect=true
  • 在文章的 frontmatter 元信息中,将 cover 字段留空,已定义了 cover 字段的则以 cover 定义优先

开始折腾

1. 修改 themes/anzhiyu/scripts/filters/random_cover.js

  • 在约 57 行增加 data.is_random_cover = true
1
2
3
4
5
6
7
if (!coverVal) {
const randomCover = randomCoverFn()
const cover = randomCover ? addUuidToUrl(randomCover) : randomCover
data.cover = cover
data.is_random_cover = true // 增加这一行
coverVal = cover // update coverVal
}

2. 修改 themes/anzhiyu/layout/includes/mixins/post-ui.pug

  • 将以下段落整体替换,注意缩进!
1
2
3
4
5
6
7
8
9
10
11
12
13
      if post_cover && theme.cover.index_enable
.post_cover(class=leftOrRight)
a(href=url_for(link) title=title style='display: flex;height: 100%;')
img.post_bg(src=url_for(post_cover) onerror=`this.onerror=null;this.src='`+ url_for(theme.error_img.post_page) + `'` alt=title style='pointer-events: none')

// 将上面那一段整体替换为下面的内容

if post_cover && theme.cover.index_enable
.post_cover(class=`${leftOrRight}${article.is_random_cover ? ' is-random-cover' : ''}`)
a(href=url_for(link) title=title style='display: flex;height: 100%;')
img.post_bg(src=url_for(post_cover) onerror=`this.onerror=null;this.src='`+ url_for(theme.error_img.post_page) + `'` alt=title style='pointer-events: none')
if article.is_random_cover
.cover-title= title

3. 修改 themes\anzhiyu\source\css\_extra\anzhiyu\custom.css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#article-container
a:not([data-fancybox="gallery"]):not(.headerlink):not(.cf-friends-link):not(.tag-Link):not(.btn-anzhiyu):not(
.no-text-decoration
):not(.auto-card-link-card) { /* 增加这一行,或者直接替换这一整段 */
font-weight: 500;
border-bottom: solid 2px var(--anzhiyu-lighttext);
color: var(--anzhiyu-fontcolor);
padding: 0 0.2em;
text-decoration: none;
font-family: auto;
}

#article-container
a:not([data-fancybox="gallery"]):not(.headerlink):not(.cf-friends-link):not(.btn-anzhiyu):not(
.no-text-decoration
):not(.auto-card-link-card):hover { /* 增加这一行,或者直接替换这一整段 */
color: var(--anzhiyu-white);
background: var(--anzhiyu-main);
box-shadow: var(--anzhiyu-shadow-lightblack);
border-radius: 0.25em;
text-decoration: none;
}

4. 增加 CSS 样式

  • 还是 source/css/article.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
/* ===== 文章卡片封面标题叠加 ===== */
.post_cover {
position: relative;
}

/* 随机封面:深灰半透明遮罩(仅对随机封面生效) */
.post_cover.is-random-cover::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
pointer-events: none;
z-index: 1;
}

.cover-title {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 90%;
color: #fff;
font-size: 1.8rem;
font-weight: bold;
text-align: center;
z-index: 2;
pointer-events: none;
word-wrap: break-word;
line-height: 1.4;
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}

大功告成

至此,已完成所有修改,hexo 经典的一键三连 hexo clean && hexo g && hexo s 先预览一下,没问题就部署吧

#主题 #建站 #博客