- 手写 Canvas 星空,按面积控制粒子数并支持减少动效降级
- 项目与文章全部由 Markdown 驱动,Zod 在构建期校验
- 部署在 Cloudflare Pages,push 即发布
背景
需要一个能长期维护的入口:简历是静态 PDF,GitHub 只展示代码,社交平台信息零散。更重要的是,这个站点本身可以当作前端能力的样本——它得足够快、能在手机上读、代码经得起看。
做了什么
四个模块:个人介绍、技能、项目、博客。深色主题 + 星空背景,多端适配。
内容即数据。项目和个人信息放在 src/content/ 与 src/data/,src/content.config.ts 用 Zod 定义字段。新增一个项目就是加一个 Markdown 文件,不需要碰组件;字段写错时构建直接失败,而不是上线后看到 undefined。
星空分三层:CSS 径向渐变垫底(无 JS 也能看到星点)→ Canvas 星点与闪烁 → 滚动视差。粒子数按 宽 × 高 / 9000 计算,移动端上限 140;页面隐藏时暂停,prefers-reduced-motion 下只渲染一帧静态星空。
零框架运行时。所有交互——主题切换、移动端菜单、筛选、目录高亮、灯箱、复制——都是原生 TS,总量不到 300 行,由 Astro 按需打包。
技术方案与取舍
- 选 Astro 而不是 Next.js:这是内容型站点,不需要 React 运行时,静态输出能把首屏成本压到最低。
- 不引入 Tailwind:页面数量少,一套 CSS 变量加 BEM 更可控,也避免类名噪音。
- 代码高亮用 Shiki 在构建期完成,运行时零 JS;复制按钮用事件委托,一个监听器处理所有代码块。
- 目录高亮用
IntersectionObserver而不是监听scroll计算位置,长文章滚动时不掉帧。
结果
Lighthouse 移动端性能 95+,首屏 JS 约 30KB(gzip),CLS 接近 0。从写第一行到上线用了约两周,期间最耗时的不是页面,而是星空在低端设备上的性能调试。
复盘
下次会把设计 token 更早定稿。中途改过一次主色,CSS 里因为坚持用变量所以改动很小,但线框图和实现已经有些脱节。另外验证「无 JS 可读」让我发现了两处内容被脚本挡住的问题,这类检查应该写进固定流程。