一开始,我以为自己在做一个博客。真正开始动手后,才发现我是在安排光线、距离,以及读者愿意停留多久。页面只是最后出现的形状,更早发生的是一连串关于边界的决定。
一座博客真正困难的部分,不是把内容放上去,而是让读者愿意在其中停留。
先写下边界
我没有从组件库开始,而是先写了一页“不会做什么”。这张清单后来比最初的线框图更有用:它让每次增加效果时,都能回答这个效果究竟服务于谁。
- 不用持续运动抢走阅读注意力;
- 不把文章元数据藏在只能悬停发现的地方;
- 不让主题切换改变内容层级;
- 不为了视觉完整性锁死字体大小。
内容也采用同样的约束。文章只维护必要的 frontmatter,阅读时长、目录和相关文章都由构建过程派生。这样作者只需关心 title、date 和真正要写的正文。
| 决定 | 曾考虑的方案 | 最终原因 |
|---|---|---|
| 本地 MDX | 在线 CMS | 离线可写,版本历史清楚 |
| 服务端读取元数据 | 浏览器端请求全部文章 | 首屏更轻,也避免正文泄露给列表页 |
| 少量主题变量 | 每页独立配色 | 保持气氛一致,维护成本更低 |
| SVG 封面 | 大体积照片 | 可程序化生成,缩放仍然锐利 |
把背景与内容分层
所谓“会呼吸”,不是让所有东西都漂浮。我的背景分为远处色雾、中层光斑和近处细微颗粒,正文则停在稳定的网格上。即使删掉所有装饰,标题、摘要与阅读顺序也必须成立。
:root {
--room-bg: #f4f0e8;
--room-ink: #24262b;
--room-glow: rgba(125, 156, 171, 0.28);
--room-panel: rgba(255, 255, 255, 0.62);
}
.reading-surface {
background: var(--room-panel);
color: var(--room-ink);
backdrop-filter: blur(18px);
}
Server-first 的组件边界
文章读取、排序和目录生成都留在服务端。只有搜索、视图切换和主题设置需要进入浏览器。判断标准很朴素:如果一块界面不需要响应用户输入,它就没有理由承担额外的客户端成本。
我用三步检查每个新组件:
- 它是否真的需要状态或浏览器 API?
- 它的数据能否在构建期确定?
- 关闭 JavaScript 后,核心内容是否仍可抵达?
六次打磨后的结论
第六次重做首页时,我终于接受一个事实:个人网站不会在“完成”那天变好,它只会在持续写作后变得可信。现在的版本保留了未填满的位置,也保留了未来修改的余地。
真正让我满意的并非某个动效,而是新增一篇文章只需创建一个文件。复杂度被留在系统内部,写作者面对的是一张干净的纸——这大概就是我想要的“房间感”。