社交媒体

敬山月主题二改记录

敬山月主题二改记录

基于 moonlit-mountain 二开的 Halo 博客主题「敬山月」,这段时间陆陆续续改了不少细节,记一笔都动了什么。

开屏动画主题色适配

原版开屏动画所有颜色硬编码——纯黑背景、白色圆环、固定蓝金配色,切到月白浅色主题时整个开场就是一坨黑。改成全部走主题变量:背景用 `var(--page)`,两个圆环用 `rgb(var(--accent-a-rgb) / 0.4)` 和 `rgb(var(--accent-b-rgb) / 0.35)`,图标和文字分别取 `var(--accent-a)`、`var(--text)`、`var(--muted)`。深夜是深色开场,月白是浅色开场,自动跟着月相走。

```css
.intro-overlay {
  background: var(--page);
}
.intro-ring--a {
  border-color: rgb(var(--accent-a-rgb) / 0.4);
}
.intro-ring--b {
  border-color: rgb(var(--accent-b-rgb) / 0.35);
}
.intro-icon {
  color: var(--accent-a);
}
.intro-title {
  color: var(--text);
}
.intro-sub {
  color: var(--muted);
}
```

同时加了 `sessionStorage` 判断,同一标签页首次进入播一次,刷新不再重复放,避免每次 F5 都被动画打断阅读。

上一篇 / 下一篇卡片封面图

原版上下篇导航就是两块纯色面板,跟文章本身完全脱节。改成有封面图的文章自动把封面当背景,叠一层 135° 深色渐变遮罩保证文字可读。默认状态封面灰度处理,鼠标悬停恢复彩色,卡片上浮 2px,边框变月相金。

Thymeleaf 模板里动态拼背景图:

```html
<nav class="post-nav" th:with="cursor = ${postFinder.cursor(post.metadata.name)}">
  <a th:if="${cursor.hasPrevious()}"
     th:href="@{${cursor.previous.status.permalink}}"
     th:style="${!#strings.isEmpty(cursor.previous.spec.cover)
       ? 'background-image: url(' + cursor.previous.spec.cover + ')' : ''}">
    <span th:text="#{page.post.previousPost}">上一篇</span>
    <strong th:text="${cursor.previous.spec.title}"></strong>
  </a>
</nav>
```

用属性选择器区分有无封面图,没封面的文章保持原来的简洁面板样式,不套遮罩也不灰度:

```css
.post-nav a {
  position: relative;
  overflow: hidden;
  border-radius: 16px;
  background-size: cover;
  border: 1px solid rgb(var(--surface-rgb) / 15%);
}
.post-nav a[style*="background-image"] {
  filter: grayscale(1);
}
.post-nav a[style*="background-image"]:hover {
  filter: grayscale(0);
}
.post-nav a[style*="background-image"]::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg,
    rgb(0 0 0 / 70%) 0%, rgb(0 0 0 / 50%) 60%, rgb(0 0 0 / 35%) 100%);
}
```

继续阅读卡片高光边框

继续阅读"区域的文章卡片原来 hover 只有一条底部细线,太素了。改成鼠标跟随的渐变高光边框——鼠标移到哪,边框上就有一团月相金到蓝的光跟着走。实现思路是卡片上挂两个 CSS 变量 `--mouse-x` / `--mouse-y`,JS 监听 mousemove 更新位置,CSS 用径向渐变画在边框上。

```js
document.addEventListener("mousemove", (e) => {
  const card = e.target.closest(".recent-card");
  if (!card) return;
  const rect = card.getBoundingClientRect();
  card.style.setProperty("--mouse-x", `${e.clientX - rect.left}px`);
  card.style.setProperty("--mouse-y", `${e.clientY - rect.top}px`);
}, { passive: true });
```
```css
.recent-card { border: 1.5px solid transparent; }
.recent-card::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1.5px;
  background: radial-gradient(
    220px circle at var(--mouse-x, 50%) var(--mouse-y, 50%),
    rgb(var(--accent-a-rgb) / 0.9),
    rgb(var(--accent-b-rgb) / 0.5) 40%,
    transparent 70%
  );
  -webkit-mask: linear-gradient(#fff 0 0) content-box,
                 linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box,
        linear-gradient(#fff 0 0);
  mask-composite: exclude;
  opacity: 0;
  transition: opacity 300ms ease;
}
.recent-card:hover::before { opacity: 1; }
```

关键是用 `mask-composite: exclude` 把渐变裁成只有边框那 1.5px 可见,中间实心背景不被光效穿透。

其他零碎

导航栏滚下去自动隐藏、往上滚恢复显示;关于我面板用文章封面淡化做背景、渐变遮罩边角对齐修复;社交图标 Iconify URL 斜杠兼容修复。搜索弹窗是 Halo 插件的 Shadow DOM,外部 CSS 穿不透,试过注入 style 也没生效,最后放弃保持原生。

版本停在 1.0.1,后面有新想法再继续磨。