Ethereal 主题魔改
Ethereal 主题魔改全记录:从瞬间条到标签云
本文记录本站 Halo 博客主题 Ethereal(Astro 主题,fork 自 AloneNanNan/halo-theme-ethereal,基于 Fuwari 设计)从 v1.0.7 到 v1.0.16 的全部自定义魔改:每个功能的魔改处(涉及文件)、功能说明与实现原理。
魔改总览
| 功能 | 引入版本 | 魔改处(核心) |
|---|---|---|
| 瞬间滚动条(全站固定) | 1.0.8 → 1.0.15 多轮迭代 | 新增 MomentMarquee 三件套,改 MainGridLayout / app.ts / global.css |
| 标签彩色化 + 球形标签云 | 1.0.8 → 1.0.16 | 新增 tag-colors / tag-sphere 四件套,改 settings.yaml / Tags.astro / 7 处标签元素 |
| 切页 is-home 同步修复 | 1.0.11 → 1.0.13 | app.ts(Swup 钩子)、global.css |
| 天气组件错误透传 | 1.0.9 前后 | Weather.astro |
| 手机端标签回退原版 | 1.0.16 | tag-colors.ts / tag-sphere.ts / Tags.astro / tag-sphere.css |
一、瞬间滚动条(全站固定、跨页不闪)
魔改处
- 新增:
src/components/widget/MomentMarquee.astro(组件)、src/styles/moment-marquee.css(样式)、src/utils/moment-marquee.ts(数据拉取) - 修改:
src/layouts/MainGridLayout.astro(挂载位置)、src/scripts/app.ts(初始化)、src/styles/global.css(banner 位移同步)
功能
页面顶部一条「瞬间」动态滚动条:内容从左到右无缝循环滚动,横跨两侧栏与文章卡片之上;整条可点击进入 /moments 瞬间页;随页面切换常驻不闪、动画不中断。
详细介绍(含多轮迭代)
- v1.0.8 初版:仅首页文章列表上方显示。数据不在服务端注入,改为客户端
fetch('/moments/rss.xml')(同源无跨域),解析<item><description>去 HTML 截断后填充,双份复制 track 实现无缝循环,按内容宽度计算动画时长。 - v1.0.9 全站固定:把组件从
index.astro移到MainGridLayout,渲染在#main-grid之上、#swup-container之外——Swup 切页只替换容器内内容,因此瞬间条跨页持久、动画不中断;加data-mm-init幂等守卫,切页不重建。 - v1.0.10 首页间距修复:首页带 banner 时
#main-grid被.is-home.enable-banner整体下推 376px 给 banner 让位,而瞬间条是网格的兄弟节点不受影响,导致中间凭空出现 ~360px 空白。修法:瞬间条包裹层加moment-marquee-anchor类,同条件下同步translate-y。 - v1.0.11 → 1.0.12 切页卡顿根因:切页时瞬间条与网格仍被错误下移几秒。线上实测(浏览器 CDP 时间线)发现
visit:start钩子里new URL(visit.to.url)抛Invalid URL——Swup 的visit.to.url是相对路径,抛错被catch吞掉导致body.is-home同步从未执行。修法:新增pathnameOf()兼容相对/绝对路径提取,在visit:start用目标 URL 提前同步body.is-home,并加content:replace兜底钩子。 - v1.0.13 过渡同步:给
moment-marquee-anchor补上与#main-grid一致的transition duration-700,让瞬间条和文章卡片从同一时刻同步滑动,消除"瞬间栏先定位"的错位感。 - v1.0.14 → 1.0.15 右侧图标:瞬间条最右侧加相机图标("记录瞬间")。过程中踩了 Tailwind 任意值语法坑:
icon-[material-symbols--auto_awesome]里的下划线会被当作空格导致图标规则永远生成不了,且 material-symbols 图标集构建时加载不稳定——最终改用手写内联 SVG(线性描边、currentColor随主题变色、呼吸闪烁动画),100% 稳定显示。
二、标签彩色化 + 球形标签云
魔改处
- 新增:
src/utils/tag-colors.ts/src/styles/tag-colors.css、src/utils/tag-sphere.ts/src/styles/tag-sphere.css - 修改:
settings.yaml(styleSwitches.tag_style三选项下拉)、src/components/widget/Tags.astro(球形分支 + 移动端列表副本)、src/scripts/app.ts(初始化)、7 处标签元素(PostMeta.astro、archives.astro、moment.astro、moments.astro、photo.astro、tags.astro的条件类)
功能
后台「样式 → 标签样式」新增三选项:
- 原版:主题默认标签
- 彩色标签:标签字体按名称哈希得到稳定色相,同一标签全站同色、刷新不闪,亮/暗模式自适应
- 球形标签云:3D 旋转球体,标签均匀分布在球面,支持鼠标拖拽甩动、悬停互动、近大远小、彩色辉光
详细介绍
- 彩色标签:用标签标识(优先 href,其次文本)做哈希 → 0~359 色相 →
hsl(),只改字体颜色(不动背景/描边,避免破坏主题卡片视觉);由initTagColors()读取theme.config门控,非 colorful 直接跳过;监听 Swuppage:view与暗色切换重新着色。 - 球形标签云:Fibonacci 球面分布保证均匀;每帧按深度(z 轴)计算缩放(0.6
1.3)与透明度(0.351);自动旋转 + 鼠标位置影响转速 + 拖拽惯性;prefers-reduced-motion时停转。球形模式下侧栏标签组件不折叠(避免裁球)。 - 手机端回退(v1.0.16):
<768px时 JS 跳过着色/不初始化球体,Tags.astro双渲染一份原版列表(md:hidden,手机显示、桌面隐藏),CSS 隐藏球体——手机端永远只显示原版标签。
三、切页 is-home 同步修复(技术彩蛋)
魔改处
src/scripts/app.ts:新增pathnameOf()与pendingTargetPath,改造visit:start钩子,新增content:replace兜底钩子src/styles/global.css:.is-home.enable-banner .moment-marquee-anchor同步位移规则
功能
修复 Swup 页面切换时 body.is-home 类滞后导致的 "顶部大段空白、几秒后跳回" 卡顿。
详细介绍
Ethereal 的首页 banner 位移规则 .is-home.enable-banner #main-grid 依赖 body 上的 is-home 类,而 body 不在 Swup 替换的容器内。原主题只在 page:view(动画结束后)更新该类,且 Swup 更新浏览器 history 也晚于 page:view,于是切页瞬间 body 仍是旧页的 is-home,banner 位移错误作用到新页。修复链:
visit:start(动画开始前)用目标 URL 提前同步is-home;pathnameOf()兼容 Swup 返回的相对路径(new URL(相对路径)会抛错);content:replace兜底(用缓存的目标路径,不依赖 history 更新时机)。
四、天气组件错误透传
魔改处
src/components/widget/Weather.astro(+22 行)
功能
天气卡片在接口异常时透传腾讯位置服务返回的真实 status/message,而非笼统的 "服务繁忙"。
详细介绍
原实现把所有失败统一 catch 成 "天气服务繁忙",遇到 110/112/113/120 等状态码无法区分是 Key 配置问题、域名白名单问题还是 QPS 限流。改为把 [status] message 直接显示在错误卡片上,一眼定位问题(本站曾实测到 status: 120 = QPS 达上限)。
五、版本历程
| 版本 | 内容 |
|---|---|
| 1.0.7 | 上游基线 |
| 1.0.8 | 首页瞬间条初版 + 标签彩色化 |
| 1.0.9 | 瞬间条全站固定(移到 #swup-container 外)+ 标签球形云 |
| 1.0.10 | 首页瞬间条间距修复(banner 位移同步) |
| 1.0.11 → 1.0.12 | 切页卡顿根因修复(visit.to.url 相对路径兼容) |
| 1.0.13 | 瞬间条过渡同步(transition 对齐) |
| 1.0.14 → 1.0.15 | 瞬间条右侧相机图标(内联 SVG,避开 iconify 加载坑) |
| 1.0.16 | 手机端标签回退原版 |
结语:与上游共存
所有魔改集中在一个自定义分支(fork: lqbby/Halo-Theme-Ethereal),与上游 main 分支互不干扰。为了上游更新时能顺利合并,仓库内维护了 CUSTOM-PATCHES.md(改动清单 + 合并指南)和 ethereal-custom.patch(完整补丁),冲突高发点集中在 settings.yaml、app.ts、MainGridLayout.astro、global.css、Tags.astro 与 theme.yaml,合并后需重新 astro build 验证。
魔改虽好,紧跟上游更重要——功能与可维护性的平衡,才是长期持有主题的正确姿势。