惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Martin Fowler
Martin Fowler
A
About on SuperTechFans
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
aimingoo的专栏
aimingoo的专栏
T
The Blog of Author Tim Ferriss
IT之家
IT之家
罗磊的独立博客
博客园_首页
月光博客
月光博客
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Last Week in AI
Last Week in AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
量子位
Hugging Face - Blog
Hugging Face - Blog
G
Google Developers Blog
博客园 - 叶小钗
H
Help Net Security
N
Netflix TechBlog - Medium
B
Blog
Engineering at Meta
Engineering at Meta
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
V2EX
Vercel News
Vercel News
博客园 - 三生石上(FineUI控件)

桜庭夜 | 杂话铺子

林肯是黑人//豆包算命 日本纪行 Extra Edition 日本纪行 苏州探索日志 再见了,我用过的个性签名。 再见了,我用过的头像
用 Astro 重构 WordPress 博客
2026-02-14 · via 桜庭夜 | 杂话铺子

杂话铺子的功能和样式细节在快速迭代更新中,文章中有些内容已经过时。

其实这篇文章应该叫做:杂话铺子装修日志·其三

书接上回,咱换到 Argon 这个主题后……诶,现在的杂话铺子真的还能“书接上回”吗?

文章前半部分都是我在碎碎念,想要看我在重构过程中具体做了什么的读者们,可以快进到这里


Ade, WordPress. Ade, Theme Argon.

2021 年的时候,杂话铺子的博客程序从 Typecho 更换到了 WordPress,并启用 Argon 主题。WordPress 是个能满足个人博客需求的程序,Argon 是一款相当不错的 WordPress 平台上的主题。

提到 WordPress 自不必多言,它是一个功能相当强大,强大到有些臃肿的内容管理系统,它也是我第一个接触的博客程序。

至于 Argon,我对它甚是喜爱。虽然 Argon 已经四年没更新过——有什么必要更新呢?Argon 已经做到了功能完善、样式丰富。它不仅能满足博客的需求,并且它有丰富的可自定义项,顶栏、Banner、布局、小卡片、评论区……甚至连文章内的样式,标题、字体等等,都有十分多样细致的配置选项。

但是,我要和它们说再见了。

淘汰它们的主要理由,大概和五年前从 Typecho 切换到 WordPress 一样,“喜新厌旧”的情绪总在我心头搔痒。其次,从易用性和其他的个人情感出发,这次切换的理由还有:

第一,WordPress(以及其他CMS程序)的文章发布流程复杂。

虽然我是一年也不更新几篇文章的懒人博主(逃),但是每一次在 WordPress 上更新文章的流程都很痛苦。

在接触了自建站和某些互联网服务停止服务这些事情后,我大抵是意识到互联网上的数据是多么不可靠、不可控的东西。所以从早期开始,我就习惯在本地撰写文章,而不是使用 Typecho 或者 Wordpress 自带的编辑器。一开始我使用的是 Typora,后来接触了 Obisidian 之后,就开始使用 Obsidian 来编辑和管理杂话铺子上的内容。不只是文字内容,文章的插图我也选择保存在本地,而不是引用图床链接插入文章。

这与 WordPress 的发布流程格格不入,无法兼容。每次更新文章,我都需要将本地 Markdown 文件中的文字复制、粘贴到 WordPress 文本编辑器;WordPress 的编辑器支持富文本粘贴,这一步到还算是省心。而图片部分,才是令我头大的地方。最早我使用 Typecho 和 WordPress 内置的媒体库来上传和管理图片,后来接触了CDN、对象存储和图床程序,购买图床程序 Chevereto 来上传、管理图片。

但是 Chevereto 不太“干净”,它会将图片处理成小、中、大、原始多个分辨率版本存储,并且这个功能无法禁用。而且,某次我操作失误,删除了在 Chevereto 创建的文章插图相册,没想到把对象存储中的图片文件也删除了——再见了,Chevereto。随后我便换成了另一个图床程序,兰空图床(Lsky Pro) 。至于那些由于从 Chevereto 跑路后保存在对象存储中的图片,虽然它们不能用兰空图床浏览,但这无关紧要,只要它们能被访问就可以了。直到最近我意识到——对啊,图片能被访问就行了。那我还要这个图床程序作为中间件干嘛呢?部署的 Chevereto 覆灭之后,我就不再用图床程序管理图片,而只用它的上传功能。于是,后来我干脆把兰空图床停用了,使用对象存储自家的上传工具。

这么一顿折腾下来,算上那些最早我用博客程序的媒体库上传的图片,我的对象存储中的目录结构早就混乱不堪,图片散落在各种命名规则的目录下,但是反正……反正只要能访问就好了。

让我们把扯远了的话题收回来。

每次我要在文章中插入图片,我首先需要将本地图片上传到对象存储中,获得图片外部链接,然后再在博客程序的文字编辑器中重新插入图片。这真是太痛苦了,尤其是我去年写了一篇动态博客搭建指北:指导8年前的我搭建个人博客,教程类文章需要的插图数量远超想象(这么说来,mikusa 简直是超人,草)。你说我为什么不用 PicGo?算了吧,我对我的长性实在没什么自信。我会永远保持使用同一家对象存储、外链域名不变——得了吧,别把我自己骗了。再加之上文说过的“我大抵是意识到互联网上的数据是多么不可靠、不可控的东西”,我才不要把数据绑定在一个互联网服务上。

还有,如果我在文章发布后发现文章内有需要修改的地方,我又得在 WordPress 和本地两个地方修改。

我宁愿去原神中采摘3个世界的清心、琉璃袋和琉璃百合,我也不想要重复把文章搬迁到 WordPress 的过程了!

第二,Argon 被我魔改了好多地方,或许是魔改的代码质量或者实现逻辑有问题,又或者是我电脑有些烂(也……也不至于吧),有时候会感觉杂话铺子卡卡的,于是一念之间,有了重新装修杂话铺子的念头。

第三,杂话铺子想要变得特别

对于杂话铺子的文章和样式的参考、借鉴、模仿,我一般都不会介意——直到有人把这些全都干了。

Argon 是 solstice23 创作的主题,在 GitHub 上分发,大家都可以使用它,这很好。我很喜欢这个主题,我对这个主题添加了许多个人改动,我也将这些改动以杂话铺子装修日志的形式分享了出来,我也会回复评论区中 Argon 主题相关的问题。

杂话铺子是一间由桜庭夜经营的贩售闲言碎语的小店,是我的个人博客,在互联网上呈现,可以被搜索引擎收录,允许被 AI Bot 检索。

我觉得,杂话铺子,以及桜庭夜和我,已经足够自由、开放,包容,且具有互联网精神了。

但是你不能同时做出以下全部行为:你不能理所应当地将 Argon 中如此丰富的布局样式配置项,设置的和杂话铺子一样;不能将菜单结构设置的和杂话铺子一样,不能将菜单项目的 Font Awesome 的图标都设置的和杂话铺子一样;尤其,你不能照抄桜庭夜的“关于”页面。我倒是好奇,你是出于什么考虑,就连“关于”页面,这个自我介绍页面的每一句话都要模仿。

最后,你不能在询问了如何自定义 Argon 主题样式的问题后,在复刻了杂话铺子后,还来问“我可以转载这个文章到我的博客上吗”。

我非常难过。

出于以上所有原因,我要对 WordPress 和 Argon 说再见了。我要重新设计撰写和发布文章的流程。我要和难过的心情说再见了。

旧的杂话铺子

在开始之前

如果想要摆脱 WordPress 发布文章的繁琐流程,那就让博客变得安静——不再需要复杂的 WordPress 数据库表交互,让Markdown文件成为页面本身,让博客静态化吧。

我在搭建博客的教程末尾留过一个关于静态博客的引子,或许从那时,亦或者更早的时候我就已经想要将杂话铺子迁移到静态博客框架上了。

静态博客的性能、速度优势对于杂话铺子来说倒是其次,静态化带来的好处中,我喜欢的是更平滑的文章发布流程、更充足的异地备份、全新的一把梭便捷的部署流程,以及最让我有动力的一点——有趣。无论是数据迁移、功能实现还是编写样式,这些过程对于不会编程的我来说,都很有趣。

静态博客框架很多,多年前我刚开始建站的时候,见过最多的是Hexo,但是它现在似乎不太常见;我比较眼熟的静态网页生成器还有 Hugo,杂话铺子的邻居中也有几位好友在用。

另,我统计了一下杂话铺子的友链各位的博客框架,Typecho 有 8 位,Hexo 有 3 位,Hugo 有 2 位,WordPress 有 2 位,独立开发或其他框架有 3 位。这么一看 WordPress 有些……小众?

最后,我选择了 Astro 作为杂话铺子的静态网页框架。

选择 Astro 最初的原因,是看到了 Retypeset 这个 Astro 框架上的主题,看起来非常棒;因此我开始了解 Astro 框架,翻看文档。Astro 的官方文档写得相当清晰明了,还有中文版本,在入门章节中还专门有一节“教程:搭建一个博客”——就是这个指引教程,直接让我动了用 Astro 重构杂话铺子,以及创建一个自己的主题样式的想法。

在真正开始动手之前,还有一个小小的动力在背后轻轻地推动:现在杂话铺子正在使用的,全新绘制的网页徽标。

2025年2月19日,在背日语单词时的走神之闲暇,我在草稿纸上画出了这个徽标的雏形,用Illustrator重绘后,随即就决定用它作为杂话铺子的新网页徽标。

并不是看厌倦、不喜欢旧的徽标了,而是旧徽标存在著作权问题。

好吧,虽然由看BT下载动画、热爱收集图片、给博客插入版权音乐、使用画师们的图片作为文章封面的我口中,说出这种话有点奇怪(逃),但是杂话铺子从近乎建立以来使用的网页徽标的原图,是画师mocha的作品春の窓(春之窗)。我很喜欢这幅画,春天、樱花和破碎的玻璃,似乎这么多年下来,也成为我对杂话铺子的印象了。

想要替换掉原来的徽标的原因,大多并不是出于什么道德谴责和罪恶感,只是使用别人的画作当做个人网站的徽标,于情于理,于画师,于我,都有些不是个滋味。嘛,我并不是想道貌岸然地谴责这个广泛存在的行为。我深刻地理解朴素的对于作品权利的侵犯大多是出自于朴素的“喜欢”的情感。这听起来有点悲哀,但这是事实。我们会把喜欢的图片作头像,喜欢的音乐作视频的BGM,宛若暴露自己内心深处的癖一般将自己阴暗潮湿的爱展示给别人——好吧,其实没那么不堪,但是意识到这个问题后,就会下意识地想要回避。总之,既然我一直在意这个事情,那就把原来的徽标换掉吧。

那么,这个由抽象图形构成的新徽标到底是何意味有什么含义呢?都说了新徽标的草稿是在“走神之闲暇”创作的,而且由作者来解释也有些奇怪,就请诸位读者自行解读吧(其实就是没想好怎么编,逃)


用 Astro 重构杂话铺子

将动态博客重构为静态博客的过程其实没那么复杂,大致有这 4 个重要工作:

  1. 数据迁移
  2. 功能复现
  3. 样式实现
  4. 部署

虽然杂话铺子的文字尚且不含任何AI生成内容,但姑且说一下:下文中所有提及的与“写代码”和“编程”相关的动作,皆是由 Gemini 和 Claude 辅助完成。

数据迁移

文章和图片

杂话铺子的文章都留有本地文件,而且我曾经为了体验 Obsidian 中的 DataView 插件,还给每篇文章加过简单的几个 Frontmatter。至于文章中插入的图片,在 Obsidian 中我有一个专门存放插图的目录,虽然因为图片命名规则混到导致乱成一锅粥,但至少有清晰的项目目录结构。按理来说,将文章数据从 WordPress 数据库提取出来创建本地文件,并为文章文件附上 Frontmatter 是最大的工作量——但是我两个都完成过了诶,岂不是这一步会很轻松?就是这个错觉,让我浪费了许多时间。

虽然我确实已经有了文章、图片的本地文件,以及标题、分类和标签的文章 Frontmatter,但是想要构建一个博客的话,这三个字段完全不够。考虑到链接样式和链接重定向需求,用于生成链接的文章别名更是重中之重。我先用脚本批处理了原来手动添加的字段并添加了标题字段后,就开始手动给文章添加别名字段了。我想,我这种月更甚至季度更新的博主应该没几篇文章对吧……对,对吗?早知道还是用脚本从 WordPress 数据库中提取文章内容和各个字段的信息就好了,哭。

不过手动检查的时候,倒是发现了之前设置的别名的拼写错误,算是意外收获了。

除了文章别名,文章封面图片字段也让我折腾好久。早知道,也写个脚本处理了……

既然说到封面图片了,那就来谈谈目前新的杂话铺子的图片是怎么处理的吧。上文中提到,我长期以来是把图片上传到对象存储中,然后利用图片外链插入文章。而现在转为静态框架,能用本地文件构建网页,那么我目前是选择不再使用对象存储了。因为我之前本地的图片就是通过本地文件插入文章,又将图片存放在一个固定的目录中,所以我直接把这个图片目录移动到 Astro 项目的src/assets目录中,这样就能便捷的将图片插入文章而又不用考虑网页发布的问题了。

我有很多图片文件名中含有空格,而空格的存在会在各种奇怪的地方导致解析问题,最后用脚本处理了这个问题和相对路径……总之,文件命名格式一定要多加注意。

评论数据

此前稍微接触过一些静态博客会用的评论系统,要求登录评论系统的如Disqus、Giscus,对于杂话铺子来说不合适。一是显然对于本来就收不到几个评论的杂话铺子来讲要求访客登录评论有些大费周章,二是这些系统的数据想要迁移出来并不容易。至于其他的为人所知的评论系统还有 Waline、Twikoo 和 Artalk。Waline 看起来不错,功能丰富,部署容易,这些优点 Artalk 也都有;而 Twikoo 的文档看起来有点寒酸。

在各家功能大差不差的状况下,Google Gemini 老师推荐我使用 Waline,但我最终选择了 Artalk 作为新杂话铺子的评论系统。一则是 Garden of Outlier 的评论系统就是 Artalk,看起来非常不错。二则是 Artalk 的默认 UI 更得我心。虽然样式都能通过 CSS 覆盖修改吧,但是当我看到 Waline 文档下方评论的“你认为这篇文章怎么样?”区域那几个大黄脸表情,我就已经想要退避三舍了。最后则是无论 Waline、Valine 还是 Twikoo,它们都很强调可以利用各种免费平台部署,而说来有趣,Valine 依赖的 LeanCloud 在上个月宣布停止对外提供服务。Artalk 则由于程序特点,需要独立部署。嘛,总之依然是由于对网络服务的不放心,以及出于数据的可迁移性考虑,Artalk 反倒更赚我的好感。

从 WordPress 迁移到 Artalk 的过程大体比较丝滑,Artalk 官方提供了数据转换工具 ,通过十分简单的步骤就可以将 WordPress 中的评论迁移到 Artalk 中。需要注意的是 WordPress 中位于垃圾和回收站中的评论不会被迁移。之前杂话铺子遇到一些有趣但是不宜展示的评论,被我放在垃圾评论中“收藏”起来。为了让这些评论能顺利迁移到 Artalk 中,又不让它们展示出来,我得把它们设置为“待审”状态。

通常来讲,评论的迁移到这里就结束了。在 Artalk 中配置好站点名称、URL和评论邮件通知,就可以等着在新的杂话铺子中“开箱即用”了。但是杂话铺子的评论区好死不死还有一些额外功能:评论区表情,以及“悄悄话”。

很遗憾的通知各位读者,由于技术限制,原杂话铺子评论区中的“悄悄话”功能即日下线。对于之前的悄悄话评论,将做隐藏处理,这部分工作还在进行中。

是的,虽然我怒撰四千字展示了一个“悄悄话” 无效化的示范性判例,但是因为本人代码能力有限,不得不下线这个功能。

至于评论区表情,会放在下一章“功能复现”中讨论。

功能复现

评论区表情

我在第一篇装修日志中曾提及评论区表情的迁移相关事项。那时是从 Typecho 的 Mirages 主题迁移到 WordPress 的 Argon 主题。这两个主题对于插入表情的语法选择和逻辑处理十分相似,所以迁移过程比较无痛。而 Artalk 与这二者的评论区表情实现方式就大相径庭了:

  1. 之前的评论表情插入语法是::2233:wuyu::,而Artalk 的插入语法是:[2233_speechless]
  2. 之前的插入语法::2233:wuyu::会原封不动的写入评论数据库中,图片元素的转换和插入是在前端实现的。而 Artalk 的插入语法:[2233_speechless]会在后端直接处理成img元素写入数据库中。

这就令人头大了。我原本以为只要像之前一样,把原来数据量中的插入语法替换成新的插入语法就行,但没想到要替换成具体的img元素。

那么,既然要写很多行 SQL 语句,那干脆就麻烦到底吧。细心的读者或许注意到了,杂话铺子之前的表情命名是混乱的,夹杂着中、日、英三语。如果表情图片加载有问题,那读者仅看这些表情名称,恐怕是难猜到它的意思。所以这次干脆把所有表情名称都用英文重命名了一遍。

在实现评论区表情的过程中,有三点需要注意:

  1. 如果考虑到数据的兼容性和可迁移性,最好不要实现评论区表情的功能
  2. Artalk 默认建议的表情命名是不含“表情包”名称的,它只解析key中的名称。为了避免多个表情包有相同命名的表情,导致混乱,所以我建议在key中写上表情包的名字。
  3. 如果表情文件是和网站放在同一个域下的话,那么我建议在表情图片链接字段val中只填写没有域名的路径,如“/assets/stickers/2233/wonder_22.webp”,以实现换域名跑路的便利。

说起来,我介意“表情包”这个叫法很久了。因为大家似乎对于一张图片也会称之为表情“包”。可是,一张图片怎么能算个“包”呢?那明明是一张表情图片呀。只有很多张图片合起来,才能称之为“表情包”吧!

文章内音乐

我已经很少在文章中插入音乐了,因为使用 MetingJS 和 Aplayer 直接加载音乐流媒体平台的资源总是会受到会员限制;而找音频文件、专辑封面图片、歌词文件将文章内音乐本地化又有些麻烦。但是考虑到未来有可能的使用,以及支持历史内容,都应该把这个功能实现了。

Typecho 和 WordPress 上都有现成的插件,而在 Astro 中的最佳实践或许是创建一个 MetingJS 的 Astro 组件。但是 Markdown 文件不能直接使用 Astro 组件,除非将文章文件换成.mdx。我比较介意其他 Markdown 笔记软件对mdx的支持,所以我还是想保持 Plain Markdown。不过 Markdown 中可以直接插入 HTML 标签,而 MetingJS 的用法实际也是利用<meting-js>标签,所以最后决定直接在文章中添加 MetingJS 标签了。

记得曾经的 Aplayer 会有无刷新页面网站的重载问题,但是现在似乎由 MetingJS 修复了,因此不需要额外实现重载,只要引用 MetingJS 和 Aplayer 的 JS 即可。

部分音乐由于懒得找版权限制暂时用嵌入式 Spotify 引用,未来或许会替换成 MetingJS 实现。

图片插入样式&画廊&灯箱

对于长宽比较大的纵向长图,如果不加以限制,那简直是灾难。

图片占用过多页面篇幅的问题,因为图片的比例是固定的,所以我试图用width: 80%来变相控制图片高度,以及图片收窄显示的效果在文章中是挺不错的。

但既然主要目的是限制图片占用页面篇幅,而杂话铺子的页面又是纵向浏览的(草,说起来最初我想让杂话铺子横向滚动浏览来着,感觉很好玩),所以现在的方案是直接限制图片的高度。虽然这会导致长图在在横向的宽幅屏幕上挤作一团,但是总比长长地占了整个版面要好吧?

在连续插入几张图片的时候,如果还是一行行以块元素显示出来,实在是占用文章页面空间。这时候就要让它们组成一个画廊比较好。之前的杂话铺子上的画廊是由 WordPress 的古腾堡编辑器实现,现在则是由一个 Markdown 解析脚本来控制图片的排列行为。简单来说,如果图片仍是以“段落”的形式插入文中(也就是前后有空行),那么图片仍被当做单图;如果有数张图片在同一个段落内,那么就会当做画廊处理。

画廊的样式逻辑主要参考了 Google Photos 这样的相册软件中,时间线上图片的排列方式,并且实现了在窄屏幕设备上的自动折行。注意,折行的行为不是“响应式”的,每行显示的图片数量是在页面加载时就计算好的。所以遇到调整窗口尺寸后,文章内图片奇怪的排版行为,就麻烦读者刷新网页试试吧。

有时候,我会给画廊起一个标题,来阐述图片之间的相关性。这个行为依然由 Markdown 解析脚本控制。脚本会判定和画廊的图片在同一个段落的文字为画廊标题。单图的标题也是这个逻辑。(等下,我为什么不直接用![alt](src)中的 alt 作为单图的标题呢?我是笨蛋呜呜呜)

原来杂话铺子中有功能丰富的灯箱(fancy box)功能,现在的杂话铺子用medium-zoom实现了简单的图片放大预览功能,仅此而已。

画廊功能

BlurHash 懒加载过渡

没错,我又尝试实现我用过的 Typecho 主题 Mirages 上那优雅的图片过渡逻辑。

在上一篇杂话铺子装修日志中,我就尝试实现过 Mirages 中的模糊过渡加载的效果,只不过效果差强人意:模糊占位图出现了,图片加载完后也成功替换了,但是过渡时却存在“闪烁”的问题。现在回想起来,应该是 jQuery 自带的 Lazyload 过渡效果不正确所导致。正确的逻辑应该是加载完成的图片淡入后,占位图再消失。总之,它们不能同时完成离场/入场动画。

而之前的逻辑除了依赖 jQuery 实现,最重要的还是云服务商提供的对象存储中图片文件的远程处理功能。云服务商帮我把原图转换生成了一个极小的占位图片,从而能作为模糊占位图来使用。而现在,杂话铺子的图片全部都保存在本地目录中,不能再依靠云服务商来处理图片。

针对这种情况,或许我可以选择以同样的逻辑来实现这个功能:在本地生成一张小尺寸占位图,然后在图片加载时调用。但这岂不是就和 Chevereto 这个随地大小便生产大小图像的家伙一样了?我才不要!于是我选择借助这个项目——BlurHash

简单来说,BlurHash 通过算法提取出图片的一个20~30字符的特征值,而更神奇的是,BlurHash还可以通过还原算法和图片对应的特征值,利用 canvas 元素绘制出一个具有原始图片特征的“模糊画面”,如此一来就实现了生成图片的模糊版本的占位图的功能。

将 BlurHash 集成到 Astro 的过程,看似困难,实则是一点也不简单(?)在与 Gemini 和 Claude 老师大战数十(或者有上百)回合后,终于实现了现在杂话铺子中的效果。原理和逻辑是在页面构建的时候同时执行计算图片 BlurHash 的脚本,然后将对应的特征值(blur-hash)写入图片元素中,待到客户端加载的时候用于绘制模糊占位图。

这还不是结束。由于需要用加载好的 img 元素替代模糊占位图 canvas 元素,所以需要一个容器包裹他们;由于文章内插图实现了画廊功能,所以需要个画廊容器来包裹图片;而画廊模仿了 Google Photos 的逻辑实现了多行画廊,所以每一行还需要个容器包裹——最后,就像大肠包小肠一样,层层叠叠的样式叠加在一起,导致了一些奇怪的 CSS 问题,尤其是在不同平台表现不一致的问题。iOS 和 iPadOS 上的 WebKit 就像敏感肌,在 PC 和 Mac 上跑的好好的样式在 iOS 上就画不出来。总结出来就是层层叠叠的height:auto导致无法获取一个具体的元素高度,所以图片容器就以 0 高度处理了,直到图片加载完后才被撑开——喂!那辛辛苦苦实现的 BlurHash 占位图过渡懒加载功能不就失去意义了吗?!好在是 Astro 处理本地图片时会获取图片的尺寸信息,这可真是帮大忙了。

啥,你问我远程图片链接插入文章怎么实现这个功能?这……这我还没研究好!什么,你还问我本地图库数量太大乃至未来数据增长导致可用性问题?这……从杂话铺子这么多年才凑出1.4GB大小的附件目录的使用情况来看,那一天似乎还遥不可及嘛。总之,我确实遇见了一些可用性、可迁移性和技术债的问题,这些待我下次再仔细研究吧。好孩子不要模仿哦。

深色模式

无需多言。只不过开启 Astro View Transitions 后,为了处理元素transition过渡效果导致的深色模式下切换时页面的闪烁问题,头都要大了。

如果要启用 Astro View Transitions,那么请谨慎地在元素上添加transition效果吧,米娜桑!

如果你因为启用 Astro View Transitions 导致了一些页面切换时的过渡动画问题,正在寻找解决方案,请一定要看到文章结尾!

衬线字体

从 Typecho 到 WordPress 再到 Astro,杂话铺子上唯一不变的就是衬线体的使用。虽然黑体无可辩解地具有更清晰的渲染和显示效果的优势,但是我就是喜欢衬线体!

之前杂话铺子的衬线体使用的是 Google Fonts 上的 Noto Serif Simplified Chinese ,可是众所周知 Google 在大陆的访问有些问题。虽然加载字体的 fonts.googleapis.com 基础设施域名似乎是位法外狂徒,但是还是存在加载缓慢的问题。

我想,这次不如干脆不用 Noto Serif SC 了,直接引用系统中的衬线字体吧。于是我在body元素上加上了font-serif类名,然后衬线字体完美地在 PC 和 Mac 上渲染,一切都这么美好——除了 iOS 和 iPadOS 设备。

我向 Gemini 老师和 Claude 老师请教,二位都一口咬定是我没在 font-family 中加入华文宋体 STSong 之类的系统衬线体字体名,导致不能正常调用系统字体,Tailwind CSS 的衬线体类名确实也不包含 STSong。即便 font-serif中的第一个就是 ui-serif,但我还是半信半疑地调试了半天,没有任何效果。

直到我读到了中文网页中的字体选型及开发指南这篇文章,我才恍然大悟,iOS / iPadOS 系统并不预装 CJK 衬线字体!或许是因为黑体在屏幕上的可读性比宋体要高。Gemini 和 Claude 两位大师,你们合伙骗我!

最后使用了 Fontsource 来方便地实现字体本地化。

顺便,在折腾博客字体的过程,修复了之前杂话铺子上的衬线体的 Bug。之前杂话铺子中的加粗字体显示效果不佳,是因为加粗字体的默认字重是 700,而我之前只引入了 400 字重的字体文件,所以加粗效果是靠算法硬拉上来,效果自然很差。还有就是引入 Noto Serif SC 后,文章内的英文单引号也会被转换成中文的单引号,导致在写“Let’s Go!”之类的东西时,显示效果不好。现在我在 Noto Serif SC 前垫了一个 EB Garamond 字体,解决了这个问题……吗?虽然这确实解决了单引号的问题,但是 EB Garamond 同时也把省略号、破折号这些在中文字体中有特殊优化处理的符号覆盖掉了!最后用 unicode-range 把单引号和拉丁字符这些选择出来,单独用 EB Garamond 显示。

加粗效果对比

英文引号对比

文章引用

通常来说,Markdown 的链接语法是 [alt](url),如果文章都放在同一级目录下,url通常使用相对路径的形式:./文章.md。在 Obsidian 中,还可以使用这样的形式[[文章名]]来引用其他文章链接。

而无论是第一种标准 Markdown 语法,还是 Obsidian 的拓展语法,在 Astro 中都不能使用。为什么?

对于 Obsidian 的拓展链接 Astro 不支持这很正常,然而如果使用标准链接的方式引用文章,最后在构建的页面里,链接会原封不动地被添加进去:http://example.com/文章1.md,然而正常来说文章的固定连接使用的都是文章别名:http://example.com/article-1/

这就导致一个很大的麻烦:虽然我可以手动使用文章别名来填写链接,但是对于我过往的本地文章,我需要调整全部的插入链接形式。而且如果我还是想用 Obsidian 来管理文章,让 Obsidian 和 Astro 中的文章文件不出现偏差,文章别名的引用方式在 Obsidian 中是做不到的。

所以,不如写一个插件来让 Astro 向标准的 Markdown 语法和 Obsidian 的引用文章语法兼容。

最终实现了这样的插入方式:

---
title: "一篇文章"
slug: "an-article"
---

# 一篇文章

这是内容。

参考我的[另一篇文章](./另一篇文章.md)了解更多。

或者使用 WikiLink:[[另一篇文章]]

样式实现

上文提到,我最初选择用 Astro 重构,是因为我想使用 Retypeset 主题。这个主题简洁、大气、优雅,还有着非常丝滑的视图过渡动画,颇具高级感。但是我无法放弃用了那么多年的文章封面!而且 Retypeset 更适合冷静、理性的偏纯文字向的博客内容,虽然这种博客看起来非常酷(比如極客死亡計劃),但杂话铺子的文章内容显然并不适合 Retypeset 这类主题。

Astro 官网上有个主题商店,里面有不少免费和付费的主题,不过在其中找到一个心仪的主题何尝不可谓是大海捞针。虽然有几个二次元插画风格的主题乍一看很亮眼,但既然想让杂话铺子变得特别,那就干脆自己实现一个样式主题好了。

主页

杂话铺子的主页样式有几个我比较想改善的地方:

  1. 侧边栏信息重复。虽然侧边栏中呈现了桜庭夜和杂话铺子的相关信息,在文章有标题结构时,目录也会在侧边栏中展示。但侧边栏的菜单内容,是和顶栏菜单重复的。而侧边栏的重复内容又不能移除,因为侧边栏在移动端承担了菜单栏的功能,所以为了保障移动端的浏览体验,我必须保持侧边栏中的菜单内容。而这种设定让桌面端的页面内容重复、繁杂。
  2. 页面背景抖动。在移动端,由于浏览器的导航栏行为通常是滑动浏览页面时就折叠收缩起来,这一来就导致了浏览器视口尺寸变化,这时页面背景就会随着视口尺寸缩放、移动。
  3. 模糊效果滥用。不仅是图片过渡加载时候有模糊效果,杂话铺子的顶栏菜单也有模糊滤镜,页面背景也会随着页面下滑过渡到模糊状态。这一堆模糊效果聚在一起,让杂话铺子的页面看起来有些……油腻?我是做不到实现出 Liquid Glass 那种晃眼、复杂却又闪烁、通透的模糊过渡效果。(在浏览器实现 Liquid Glass?来看看这个。或许需要 Chromium 才能正常浏览)

所以重构的杂话铺子样式取消了大面积的背景模糊效果和侧栏。页面背景之前就想去掉,但是一直没想好要更改成什么样式,所以趁着这次重构样式,下定决心去掉了背景。(碎碎念:感觉以后可能还会以尽量不干扰页面阅读体验的样式加回来,笑)

文章卡片

Argon 主题中文章封面图片长宽比是 16:9,这使整个主页文章列表给人的感觉比较像现代的流媒体。现在新的文章卡片将封面图片长宽比调整到 4:3,这个改动让版面更具复古感。然而这个改动是破坏性更新,因为封面图片中不乏有我自己制作的,而从前制作时都是按照 16:9 的画幅制作。比如文章再见了,我用过的头像。的封面被裁切成了“见了,用过的头”,笑死。(以后制作封面图时应该在不同画幅的重叠区域制作,这样就不用担心以后再调整画幅比例了,天才!)

文章卡片的改动还有取消了一些文章信息元素的显示:字数、阅读时间、评论数,以及浏览次数和标签。字数统计目前还在 Todo List 中,阅读时间和评论数没有添加的计划,而评论数或许未来会在文章详情页中展示出来。浏览次数和标签,我暂时下定决心要把它们砍掉了。浏览次数是从 Typecho 时期的杂话铺子就一直存在,迁移到 WordPress 后,我还把之前的文章浏览数据一个个添加回来。

如今的浏览次数统计可以由评论系统 Artalk 来实现,但我还是决定把这个功能砍掉了。一是将浏览次数在主页,看似模仿的是大平台上的播放次数之类的数据统计,但是二者的意义是完全不同的。我相信在杂话铺子这个渺小的个人博客上,没有几个访客会根据浏览次数的多寡来判断该阅读哪篇文章,浏览次数更多的功能是让我获得成就感,以及数据监控。但无论是获取成就感,还是监控浏览数据,我大可以通过 UmamiGoogle Search Console 来实现,这么一来就没必要在文章卡片上添加繁冗的元素了。二是现在的杂话铺子主页取消了分页逻辑,只展示最近的一些文章,而由于浏览次数功能依赖 Artalk,在归档页面的文章列表中添加浏览次数有点麻烦。为了保持统一性,干脆全都砍掉。

至于标签,取消它的理由大概如小氯所说,用标签管理文章会产生许多混乱,况且这么多年下来杂话铺子已经有了稳定的 5 个分类,就算这样,我每次给新文章分类时都得思考一下——所以其实现在有些文章同时属于两个分类。这都有些混乱,更不用说标签了。虽然我不愿意继续打标签,以及文章卡片上不再展示标签,但是在归档页面上,还是添加了标签的元素,让读者可以大概知道些文章内容信息。因此以后再打标签时,我会添加有更细致描述的标签,而不是将标签视作另一种“分类手段”。

我没有给标签创建任何路由页面,所以标签都是不可点击的,这样就避免某个标签下只有一篇文章的窘境了(逃)

文章和独立页面

文章页面的样式并没什么特别的,两侧大量的留白和窄正文宽度让阅读更能聚焦于中心文字;Markdown 渲染的 HTML 样式格式化利用了tailwindcss/typography;图片画廊、字型等内容在上文的功能复现中已经谈及。

独立页面大抵是保留了 Argon 上的样式和内容。番剧页面是否还继续保留让我有些纠结,或许以后它会换个方式存在。

部署

好了,最让我头大的地方来了,什么服务器渲染客户端渲染、适配器、 CI/CD 持续部署……听不懂。

好在 Astro 的部署参考文档写得详细,还有 Gemini 老师帮忙,过程并不痛苦。

最初是使用的是 Cloudflare 适配器,将 Astro 杂话铺子部署到 Cloudflare Workers 上,但是 Cloudflare 的网络在中国大陆访问速度不佳,白天倒是还好,而一到晚上延迟和速度都劣化很多。

现在调整后的部署策略是通过 GitHub Actions 将静态资源部署到我的线路还行的 VPS 上,大概能解决大陆访问慢的问题吧。(实测了一下,效果不好,生气)

固定链接

取消了从 Typecho 沿用至今的文件式 URL,现在的杂话铺子摘掉了页面的.html后缀,转为使用目录式的 URL 格式。

更正了部分链接的拼写错误,修改了某些页面的别名。

所有旧链接都经过了重定向处理,所以有引用杂话铺子旧的文章链接的邻居们,可以不用费时修改链接了。

现在杂话铺子的 RSS 源由@astrojs/rss生成,使用 Pretty Feed v3 默认样式表格式化 RSS 页面,比默认的一大团 xml 代码要美观些。

上次从 Typecho 迁移到 WordPress 时由于 RSS 也被刷新,打扰到了订阅杂话铺子 RSS 的大家。虽然具体不知道有多少,但在 Folo 上自搜能看到杂话铺子有 49 名订阅者。

所以为了不打扰大家,这次新上线的 RSS 我就直接让它只输出重构上线日期之后的新文章了。


大功告成?

完成这篇文章,也意味着杂话铺子的转向静态博客的重构工作也已经基本完成。

与从前切换到开箱即用的 CMS 程序或博客主题不同,这次亲手主持杂话铺子的重构(AI不可避),过程更加复杂、困难,但同时也收获了满满的乐趣。

从接触个人网站开始,就一直很羡慕有能力自定义博客样式、创作主题,甚至博客系统的人们。而且作为创作者来讲述自己创作之物,这真是太酷了,就像作家做自己文章的阅读理解题目一样酷(?)。我也一直很喜欢读这类文章,比如 Velas 电波站的 Velas Weekly Issue 系列,还有园子的 Gradient 系列,从其中能见识到、学到各种各样的功能、设计和实现思路,实在有趣。在我借由歌词海报生成器了解到一些前端知识的皮毛后,也学会修改博客主题样式,甚至也装模作样地写出“杂话铺子装修日志”这种东西,而这篇从动态博客迁移到静态博客的装修日志,就是目前最宏大的一次装修的过程的记录了。

以上就是我想分享的全部内容。杂话铺子现在还处于重构后的阵痛期,我已经尽可能保证各端的浏览体验没有明显问题。

Note

已知在 iOS 系统中,文章卡片封面图片存在渐入过渡动画闪烁的问题,折腾了半天也没搞明白为什么只在 iOS 上会出现,如果有人告诉我怎么解决就好了(逃)

2026/2/14:竟然解决好了!似乎是因为 iOS 上 浏览器视图过渡动画处理方式和其他平台不一样。添加了Astro 视图过渡动画的组件 <ClientRouter /> 后就在 iOS 上导致了上面的问题。解决方案是在由 Transition 等各种动画效果导致出现闪烁的地方,添加 transition:name="example-name" transition:animate="none"就可以了!

其实 Astro 的视图过渡动画文档中写了

并不是所有的状态都能以这种方式保存下来。即使在使用 transition:persistent 时,也无法避免在视图转换期间重新启动CSS动画和重新加载iframe

こら!桜庭夜!好好看文档啊!

如果发现其他 Bug,或有修改建议,欢迎留言告诉我。

最后的最后——

欢迎光临杂话铺子!

ディスコ・キッド (OP Ver.)

北宇治高校吹奏楽部