Skip to main content

从零到一:一个高中生的博客搭建与优化之旅

My blog journey.webp
Published on
//
23 mins read

写在前面

大家好,我是 XFffff,一名高中生。这是我第一次尝试搭建自己的个人博客。说实话,一开始我对前端开发了解得不多,只是觉得有个自己的博客很酷,可以记录学习和生活。没想到这个过程比我想象的要复杂得多,但也更有趣。

这篇文章记录了我从零开始搭建博客的完整过程,包括遇到的各种问题和解决方法,特别是今天(2月15日)一整天的性能优化历程。希望能帮到和我一样想做博客的同学。

第一步:选择技术方案

一开始我很迷茫,不知道该用什么技术。在网上搜索了很久,看了很多教程,最后决定用这套方案:

组件选择为什么选它
框架Next.js 15听说很流行,而且可以生成静态网站
样式Tailwind CSS 3.4不用写太多 CSS,直接用类名就行
内容MDX可以用 Markdown 写文章,简单方便
部署Cloudflare Pages免费!而且速度快
包管理pnpm比 npm 快,节省空间

为什么不用 Vercel?

虽然很多教程都推荐 Vercel,但我选择了 Cloudflare Pages,因为:

  • 完全免费,没有流量限制
  • 全球 CDN,访问速度快
  • 和域名管理在一起,方便

第二步:找到合适的模板

作为第一次做项目,我不可能从零开始写所有代码。在 GitHub 上找了很久,最后发现了 mengke.me 这个开源项目。

这个项目功能很完善:

  • ✅ 支持 Markdown 写文章
  • ✅ 有深色模式
  • ✅ 可以搜索文章
  • ✅ 自动生成 RSS
  • ✅ 手机和电脑都能正常显示

我把它 Fork 到自己的 GitHub,然后开始改造。

bash
# 克隆项目到本地
git clone https://github.com/WXFffff666/my-blog.git
cd my-blog
 
# 安装依赖
pnpm install
 
# 启动开发服务器
pnpm dev

打开 http://localhost:3434,看到页面成功显示,心里特别激动!

第三步:个性化定制

修改个人信息

第一件事就是把模板里的信息改成自己的。主要修改这几个文件:

1. 个人信息(data/author-info.ts

typescript
export const AUTHOR_INFO = {
  name: 'XFffff',
  description: '一个热爱学习的高中生',
  email: '[email protected]',
  identity: 'Student | Learning',
  address: {
    city: 'Guilin, China',
    flag: 'flag-china',
    timeZone: 8,
  },
  social: {
    github: 'https://github.com/WXFffff666',
  },
}

注意:不要填真实姓名、手机号、详细地址这些敏感信息!

2. 网站信息(data/site-metadata.ts

typescript
export const SITE_METADATA = {
  title: 'XFffff 的个人博客',
  author: 'XFffff',
  siteUrl: 'https://blog.the37777777.top',
  locale: 'zh-CN',
  language: 'zh-CN',
}

写第一篇文章

data/blog/202602/ 目录下创建 Hello_World.mdx

markdown
---
title: 'Hello World - 我的第一篇博客'
date: '2026-02-12'
tags: ['随笔']
draft: false
summary: '这是我的第一篇博客文章!'
---
 
## 你好,世界!
 
这是我的第一篇博客文章。从今天开始,我要记录自己的学习和成长。
 
希望能坚持下去!

保存后刷新页面,文章就出现了!那一刻真的很有成就感。

第四步:部署到 Cloudflare Pages

本地运行成功后,就要部署到网上了。这一步遇到了不少问题。

配置静态导出

Cloudflare Pages 需要静态文件,所以要修改 next.config.js

javascript
const nextConfig = {
  output: 'export', // 静态导出
  images: {
    unoptimized: true, // 必须禁用图片优化
  },
}

遇到的第一个错误

运行 pnpm build 时报错:

text
Page "/snippets/[...slug]" is missing "generateStaticParams()"

原因:项目里有个 snippets 目录,但我还没有添加任何内容。

解决:直接删除 app/snippets/ 目录,等以后有内容了再加回来。

创建 Cloudflare Pages 项目

  1. 登录 Cloudflare Dashboard
  2. 左侧菜单 → Workers 和 Pages
  3. 点击 创建 → 选择 Pages 标签页
  4. 连接 GitHub 仓库

重要配置:

配置项
框架预设Next.js (Static HTML Export)
构建命令pnpm build
构建输出目录out

绑定自定义域名

Cloudflare 会给一个 xxx.pages.dev 的临时域名,但我想用自己的域名。

  1. 进入 Pages 项目 → 自定义域
  2. 添加域名 blog.the37777777.top
  3. Cloudflare 自动添加 DNS 记录
  4. 等待 5-10 分钟生效

访问自己的域名,博客成功上线了!那一刻真的超级激动!

第五步:深色模式渲染优化(今天的重头戏)

博客上线后,我发现深色模式有严重的渲染问题:快速滚动时,文字会闪烁消失,非常卡顿。这个问题困扰了我一整天,但最终找到了解决方案。

问题现象

  • 在深色模式下快速滚动页面
  • 部分文字会闪烁、消失
  • 有些文字清晰,有些文字模糊
  • Footer 的文字清晰,但首页的文字模糊

排查过程

尝试 1:移除 PageTransition 的 transform

我发现 PageTransition 组件使用了 translate-y-2,这会创建 GPU 渲染层。

tsx
// 修改前
<div className="translate-y-2 opacity-0">
 
// 修改后
<div className="opacity-0">

结果:❌ 还是会闪烁

尝试 2:移除所有动画的 transform

检查了所有动画,发现很多地方使用了 transform

css
/* CSS 中的动画 */
@keyframes fade-in-up {
  from {
    opacity: 0;
    transform: translateY(20px); /* ← 问题所在 */
  }
}

全部改成只用 opacity

css
@keyframes fade-in-up {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

结果:❌ 还是有问题

尝试 3:移除 Greeting 的 bg-clip-text

发现 Greeting 组件使用了 bg-clip-text 和渐变动画:

tsx
// 修改前
<div className="bg-clip-text text-transparent animate-text-shimmer">
 
// 修改后
<div className="text-violet-600">

结果:❌ 还是不行

尝试 4:对比原作者项目(找到根本原因!)

我仔细对比了原作者的项目,发现了关键差异:

我的配置:

tsx
// layout.tsx
<body className="dark:bg-black">  // 纯黑 #000000
 
// background.tsx
<div className="dark:bg-[#000000]">  // 纯黑
 
// tailwind.config.js
dark: {
  bg: '#050505',  // 极致深黑
}

原作者的配置:

tsx
// layout.tsx
<body className="dark:bg-dark">  // 深灰色
 
// tailwind.config.js
dark: '#1f1f1f',  // 深灰色,不是纯黑!

发现问题:纯黑背景(#000000 或 #050505)在某些浏览器和操作系统上会导致字体渲染问题!

最终解决方案

将所有深色背景从纯黑改为深灰色 #1f1f1f

tsx
// layout.tsx
<body className="dark:bg-dark-bg">
 
// background.tsx
<div className="dark:bg-[#1f1f1f]">
 
// tailwind.config.js
dark: {
  bg: '#1f1f1f',  // 深灰色
}

结果:✅ 完美解决!深色模式滚动完全流畅,不再闪烁!

为什么深灰色不会糊?

  • #1f1f1f 虽然看起来也很黑,但它不是纯黑
  • 这个颜色值在浏览器渲染引擎中不会触发某些特殊的优化路径
  • 原作者也是用这个颜色,证明它是稳定可靠的

教训:有时候问题的根源不在代码逻辑,而在一些看似无关紧要的细节(比如背景颜色)。

第六步:图片加载优化

解决了深色模式问题后,我发现快速滚动时,下面会出现白条(内容还没渲染出来)。这是图片加载慢导致的。

优化方案

1. 预加载首屏图片

tsx
// latest-posts.tsx
{
  posts.map((post, index) => <BlogCard key={post.slug} post={post} priority={index < 3} />)
}

前 3 篇文章的图片使用 priority={true},浏览器会优先加载。

2. 添加渐变占位符

tsx
// blog-card.tsx
<div className="relative h-48 w-full overflow-hidden bg-gradient-to-br from-gray-100 to-gray-200 dark:from-[#121212] dark:to-[#1a1a1a]">
  <Image src={coverImage} alt={title} priority={priority} />
</div>

图片加载前显示渐变背景,视觉上更平滑。

3. 优化图片淡入效果

tsx
// image.tsx
<NextImage
  className={clsx('transition-opacity duration-300', loaded ? 'opacity-100' : 'opacity-0')}
  onLoad={onLoad}
/>

图片加载完成后淡入显示,更自然。

结果:✅ 快速滚动时不再出现明显的白条!

第七步:导航栏交互优化

博客基本完善后,我开始优化细节。发现导航栏 hover 时有个放大动画,但放大过程中会模糊。

问题分析

导航栏使用了 hover:scale-[1.005],scale 变换会导致字体模糊。

尝试的方案

方案 1:移除 scale,改用阴影 + 上移

tsx
<nav className="hover:shadow-xl hover:-translate-y-0.5">

结果:✅ 完全不会模糊,但上移有点突兀

方案 2:保留 scale,添加 GPU 优化(最终方案)

tsx
<nav
  className="hover:scale-[1.005]"
  style={{
    willChange: 'transform',
    transform: 'translateZ(0)',
    backfaceVisibility: 'hidden',
    WebkitFontSmoothing: 'subpixel-antialiased',
  }}
>

GPU 优化原理:

  • willChange: 'transform' - 提示浏览器会有变换
  • transform: translateZ(0) - 强制创建 GPU 渲染层
  • backfaceVisibility: 'hidden' - 隐藏背面,提升性能
  • WebkitFontSmoothing: 'subpixel-antialiased' - 亚像素级抗锯齿

结果:✅ 保留了放大效果,模糊感大幅减少!

经验总结

1. 技术选型很重要

  • Next.js 静态导出性能很好,适合博客
  • Cloudflare Pages 免费额度够用,速度也快
  • 找一个好的开源模板可以节省很多时间

2. 遇到问题不要慌

  • 先对比原作者的代码,找出差异
  • 逐步修复,每次只改一个地方
  • 分别测试电脑端和移动端
  • 善用浏览器开发者工具

3. 性能优化要系统思考

  • 深色模式问题可能是背景颜色导致的
  • 图片加载要预加载首屏内容
  • GPU 优化可以减少 transform 的模糊感
  • 不要过度使用动画和特效

4. 细节决定体验

  • 背景颜色不要用纯黑,用深灰色
  • 图片要有占位符,避免白屏
  • 动画要流畅,不能卡顿
  • 移动端和电脑端要分别优化

5. 学会阅读源码

  • 遇到问题时,对比原作者的代码
  • 理解每一行代码的作用
  • 不要盲目复制粘贴
  • 学会举一反三

后续开发:从初版到液态玻璃

博客上线之后,我以为可以歇一歇了。结果完全停不下来——每天都能想到新功能要加,新 bug 要修。从 2 月到 4 月,这个博客经历了一次又一次的迭代,最终变成了现在的样子。

功能大爆发

上线后的两个月里,我一口气加了 11 个新功能。说实话,有些功能是我自己想要的,有些是看到别人的博客觉得「这个好酷,我也要」。

阅读进度条 + TOC 增强。 文章顶部加了一个进度条,滚动的时候能看到读了多少。目录(TOC)也做了增强,在手机上变成了一个抽屉式的侧边栏,不会挡住正文。

相关文章推荐 + 系列导航。 每篇文章底部会推荐相关的文章,算法是根据标签重合度打分的。还加了「文章系列」功能,比如这篇和 TimeMark 那篇就属于「我的开发之旅」系列,可以按顺序浏览。

Sandpack 可运行代码块。 这个是我最喜欢的功能之一。文章里的 JavaScript/TypeScript/HTML/CSS 代码块可以直接运行!用的是 CodeSandbox 的 Sandpack 组件,懒加载的,不影响页面性能。

OG 图片自动生成。 分享文章到社交媒体的时候,会自动生成一张好看的封面图。这个是构建时生成的,不需要运行时渲染。

Service Worker + 离线支持。 加了 Service Worker 做缓存,断网了也能看之前访问过的页面。顺便还做了一个友链申请表单。

键盘快捷键 + Changelog + Snippets 筛选。? 可以查看所有快捷键,加了一个 Changelog 页面记录版本更新,Snippets 页面支持按标签筛选了。

这些功能加起来,提交了十几个 commit。每次加完一个功能都要跑一遍 pnpm build,确保静态导出没问题。Cloudflare Pages 是纯静态部署,任何需要服务端的功能都不能用,这个限制反而让我学会了很多静态站点的技巧。

代码规范化重构

功能加多了之后,项目结构开始变得混乱。CSS 文件散落在各处,图片目录没有统一规范,有些文件放错了位置。

我花了两天时间做了一次大重构:

  • css/ 目录统一改名为 styles/
  • 图片目录按用途分类:covers/(封面)、banners/(横幅)、posts/(文章配图)
  • 移除了没用的测试文件和示例文件
  • 把文档统一放到 docs/ 目录

重构的过程很枯燥,但做完之后整个项目清爽了很多。以后找文件也方便了。

中文标签 404 修复

这个 bug 困扰了我好一阵子。博客的标签系统支持中文标签(比如「技术」「前端」),在本地开发的时候一切正常,但部署到 Cloudflare Pages 之后,点击中文标签就 404。

排查了半天,发现是 encodeURI 的问题。之前代码里对标签做了 URL 编码,但 Cloudflare Pages 的静态文件路径不需要编码。移除了多余的 encodeURI 调用就好了。

顺便还做了一个标签显示名映射(tag-names.json),这样标签页上能显示原始的中文名称,而不是 URL 编码后的乱码。

液态玻璃 UI 改造

这是最大的一次改动。

起因是我看到了 Apple 的液态玻璃(Liquid Glass)设计风格,觉得特别好看。之前博客用的是「黑曜石玻璃」风格——深空灰背景加噪点纹理,虽然也不错,但看久了觉得有点沉闷。

我决定把整个博客改成液态玻璃风格。

一开始我想用 liquid-glass-react 这个 npm 包,但研究了一下发现它已经 10 个月没更新了,性能也不太好,还没有可访问性支持。最后决定自己用纯 CSS 实现。

液态玻璃的核心就是 backdrop-filter: blur() 加上半透明背景。我设计了 4 个层级:

css
/* standard - 普通组件 */
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(20px) saturate(1.8);
 
/* elevated - 突出组件(导航栏、卡片) */
background: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(24px) saturate(2);
 
/* subtle - 低调组件(标签、徽章) */
background: rgba(255, 255, 255, 0.08);
backdrop-filter: blur(12px);
 
/* input - 输入框 */
background: rgba(255, 255, 255, 0.12);
backdrop-filter: blur(16px);

背景色从深空灰改成了天蓝色 #bfdbfe(浅色模式)和 #1f1f1f(深色模式)。

改造过程中踩了不少坑。一开始用了 SVG 滤镜做扭曲效果,结果在某些浏览器上会出现奇怪的变形和闪烁。后来去掉了 SVG 扭曲,只保留了 CSS 的 blur 和 saturate,效果反而更好。

还有一个问题是白色边框。液态玻璃组件之前有白色边框和阴影,在天蓝色背景上看起来很突兀。我把所有组件的白色边框和阴影都去掉了,改用更微妙的透明度变化来区分层次。

最后还要把 6 个代码块相关的 MDX 组件也适配液态玻璃风格,确保代码块在新设计系统下看起来协调。

整个改造涉及了 26 个组件,提交了好几个 commit。虽然工作量很大,但最终效果我很满意。

滑动 Pill 导航指示器

液态玻璃改造完之后,我觉得导航栏还可以更酷一点。

于是加了一个滑动的玻璃药丸(Pill)指示器。当你切换导航项的时候,一个半透明的玻璃药丸会平滑地滑动到当前选中的位置。动画用了 spring easing(弹簧缓动),有一种很自然的弹性感。

这个效果实现起来不难,但调参数花了不少时间。弹簧的刚度、阻尼、质量都会影响动画的感觉,太硬了像机械,太软了像果冻。最后调到一个我觉得刚好的状态。

kbar 搜索位移修复

这个 bug 是最后修的,也是最烦人的。

博客用了 kbar 做搜索(按 Ctrl+K 打开)。kbar 打开的时候会给 body 加 overflow: hidden,防止背景滚动。但这样做有个副作用:滚动条消失了,页面内容会往右移动一点点(大概 15-17 像素),看起来就像页面「抖」了一下。

我前前后后试了好几种方案:

  1. padding-right 补偿滚动条宽度 —— 不行,因为 sticky header 的居中计算会受影响
  2. 动态测量滚动条宽度再补偿 —— 太复杂,而且不同浏览器滚动条宽度不一样
  3. 最终方案:直接用 CSS 覆盖 kbar 的行为
css
body[style*='overflow: hidden'] {
  overflow-y: scroll !important;
}

简单粗暴但有效。让 body 始终保持 overflow-y: scroll,滚动条一直在,就不会有位移了。kbar 的遮罩层本身就会阻止用户滚动,所以不影响功能。

有时候最简单的方案就是最好的方案。

写在最后

从开始搭建到现在,已经过去好几天了。特别是今天(2月15日),我花了一整天时间优化深色模式的渲染问题。这个过程中遇到了很多挫折,有时候真的很想放弃。但每次解决一个问题,那种成就感是无法形容的。

作为一个高中生,这是我第一次完整地做一个项目。虽然代码写得不够好,但我学到了很多:

  • 学会了如何阅读文档和源码
  • 学会了如何调试和定位问题
  • 学会了如何系统地优化性能
  • 学会了如何坚持下去

最重要的是,我有了一个属于自己的博客,可以记录学习和成长。

如果你也想做一个博客,不要害怕,大胆去试!遇到问题很正常,解决问题的过程就是成长的过程。

后来我把浏览量统计功能去掉了,博客现在是一个纯静态站点,部署在 Cloudflare Pages 上,简单又稳定。

希望这篇文章能帮到和我一样的初学者。如果你有问题,欢迎交流!


相关资源

下一步计划

  • ✅ 添加了 Giscus 评论系统
  • ✅ 做了 TimeMark 生日提醒系统(我的第一个 Docker 项目!)
  • ✅ 添加了 11 个新功能(进度条、系列导航、Sandpack、OG 图片等)
  • ✅ 完成了液态玻璃 UI 改造
  • ✅ 修复了中文标签 404 问题
  • ✅ 代码规范化重构
  • ✅ 完成 v2.0 全站增强(50+ 项改进,15 个 MDX 组件,Pagefind 搜索)
  • 📝 持续写文章,记录学习
  • 🎨 继续打磨液态玻璃细节
  • 🚀 探索更多有趣的项目

加油!💪