前言: 编程的乐趣不仅在于构建庞大的系统,也在于打磨属于自己的方寸之地。 这两天,我对个人的 Hexo 博客进行了深度的“外科手术式”改造。从导航栏的像素级对齐,到项目展示页的工程化解耦,每一步都贯彻了“高内聚、低耦合”的软件工程美学。本文将详细复盘所有核心技术点与踩坑经验。

一、 顶层交互重构:悬浮胶囊导航栏 (Glassmorphism)

为了摆脱传统博客沉闷的顶部栏,我决定复刻移动端 APP 的交互逻辑,实现**“左侧菜单 - 中间标题 - 右侧搜索”**的对称布局,并赋予其磨砂玻璃(Glassmorphism)质感。

1.1 CSS Flex 布局的妙用

Butterfly 主题默认在 PC 端隐藏了“三条杠”菜单(Hamburger Menu)。为了强制显示并重排顺序,我利用了 Flexbox 的 order 属性。

核心难点

  • 如何打破 DOM 结构的默认顺序?
  • 如何解决 PC 端 CSS 权重导致的 display: none 问题?

解决方案 (custom.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
/* 容器:开启 Flex 布局,准备排序 */
#nav {
display: flex !important;
justify-content: center !important; /* 让“达芬奇”三个字在正中间 */
align-items: center !important; /* 垂直居中 */

/* 磨砂玻璃质感核心 */
position: fixed !important;
top: 20px !important;
background: rgba(255, 255, 255, 0.2) !important;
backdrop-filter: blur(12px) saturate(160%) !important; /* 毛玻璃模糊 */
border-radius: 50px !important; /* 胶囊形状 */
border: 1px solid rgba(255, 255, 255, 0.3) !important;
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.15) !important;
}

/* 强制召唤三条杠,并移至最左侧 */
#nav #toggle-menu {
display: flex !important; /* 覆盖主题的隐藏规则 */
order: -1 !important; /* 🔥 核心:-1 代表插队到第一位 */
margin-right: 15px !important;
padding: 0 !important;
}

/* 隐藏原来冗余的文字菜单 */
#nav #menus {
display: none !important;
}

1.2 搜索按钮的对称定位

为了配合左侧的菜单,右侧必须放置搜索按钮以保持视觉平衡。这里涉及到 CSS calc() 函数的动态计算。

JS 动态定位 (fancy-search.js)

1
2
3
4
5
6
7
8
9
// 强制将搜索按钮定位到右侧对称位置
const searchBtn = document.getElementById('search-trigger-btn');
if (searchBtn) {
searchBtn.style.position = 'fixed';
searchBtn.style.top = '20px';
searchBtn.style.left = 'auto';
/* 距离中心向右偏移 160px,与左侧菜单形成完美对称 */
searchBtn.style.right = 'calc(50% - 160px)';
}

这是本次改造的重头戏。我需要一个专门的页面来展示“尚庭公寓”、“分布式商城”等实战项目。

2.1 演进路线:从 Hardcode 到 Tag Plugin

  • V1.0 (HTML 硬编码):直接在 Markdown 里写大量的 <div class="...">
    • 缺点:代码臃肿,难以维护,容易因缩进问题导致渲染错误。
  • V2.0 (工程化解耦):使用 Hexo 的 Tag Plugin 机制,编写自定义脚本。
    • 优点:Markdown 里只需一行代码,自动生成复杂的 HTML 结构。

2.2 逻辑层:自定义 Tag 插件

scripts/project-card.js 中,我注册了一个名为 project 的标签。它支持接收动态参数(链接、封面、标题、描述、技术栈标签)。

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
/**
* project-card.js
* 使用方法: {% project link img title desc tag1 color1 ... %}
*/
hexo.extend.tag.register('project', function(args) {
const link = args[0];
const img = args[1];
const title = args[2];
const desc = args[3];

// 动态解析不定长参数:生成技术栈标签
let tagsHtml = '';
for (let i = 4; i < args.length; i += 2) {
const tagName = args[i];
const color = args[i + 1] || 'blue';
tagsHtml += `<span class="tag-pill ${color}">${tagName}</span>`;
}

// 返回纯净的 HTML 结构
return `
<a class="project-card" href="${link}">
<div class="card-cover" style="background-image: url('${img}')">
<div class="card-overlay"></div> </div>
<div class="card-info">
<div class="card-title">${title}</div>
<div class="card-desc">${desc}</div>
<div class="card-tags">${tagsHtml}</div>
</div>
</a>`;
});

2.3 表现层:CSS 卡片样式

custom.css 中,实现了卡片的悬浮特效和标签配色。

1
2
3
4
5
6
7
8
9
10
11
/* 悬停特效:上浮 + 蓝光阴影 */
.project-card:hover {
transform: translateY(-10px);
box-shadow: 0 20px 40px rgba(66, 90, 239, 0.15);
border-color: #425AEF;
}

/* 标签配色系统 */
.tag-pill.blue { background: rgba(33, 150, 243, 0.1); color: #2196f3; }
.tag-pill.purple { background: rgba(156, 39, 176, 0.1); color: #7b1fa2; }
/* ...更多颜色... */

2.4 数据层:一行代码调用

最终,在 source/projects/index.md 中,我们只需要这样写:

1
{% project /tags/BlogDev/ /img/blog.jpg "个人博客开发日志" "记录本站从零搭建的过程。" Hexo blue Butterfly purple %}

这一步真正实现了内容与样式的彻底分离。

三、 细节体验优化

3.1 归档页与“热门”逻辑重构

原本的“热门”按钮通常指向一些复杂的统计页。为了简化逻辑并提供更好的保底体验,我将其直接重定向至归档页 (/archives/)。

同时,对归档页进行了**“去侧边栏”**处理,让时间轴内容占据全屏,配合动态波浪背景,视觉冲击力极强。

1
2
3
4
5
// source/js/fancy-search.js
const LINKS = {
hot: '/archives/', // 🔥 巧妙的逻辑替换:热门 -> 时间轴归档
// ...
};

3.2 字体与排版

全站标题引入了 Google Fonts 的 Playfair Display(意大利斜体),并强制应用了文字阴影,营造出杂志封面的高级感。

四、 踩坑与教训 (Debug Log)

在开发过程中,也遇到了一些典型的错误,记录如下以自省:

4.1 YAML 语法缩进灾难

在配置 _config.butterfly.yml 菜单时,遇到了 YAMLException

  • 错误原因:使用了中文冒号 ,以及在列表项缩进上不统一。
  • 解决:YAML 必须严格使用双空格缩进,且所有冒号必须是英文冒号,冒号后必须紧跟空格。

4.2 HTML 标签与 Markdown 冲突

在 Markdown 文件中直接写 HTML 时,如果前面有缩进(Tab 或空格),Hexo 会将其解析为代码块而非渲染 DOM。

  • 解决:HTML 标签或 Tag 插件代码必须顶格书写。

4.3 标签参数解析错误

在使用自定义 Tag 插件时,曾出现标签颜色显示为 blue 字样的情况。

  • 原因:参数顺序写反了(写成了 blue Hexo)。
  • 解决:严格遵循 [文字] [颜色] 的参数对顺序。

五、 总结与展望

通过这两天的重构,本站已经从一个默认的 Hexo 模板,变身为一个具有高度个人特色的技术展示平台。我们实现了:

  1. 工程化:通过 JS 脚本封装组件。
  2. 美学化:磨砂玻璃与流体动画的运用。
  3. 人性化:符合直觉的导航与交互。