从零构建个人博客:技术栈与架构详解
一、引言
背景
在当今数字时代,个人博客不仅是展示专业技能的窗口,也是记录个人成长和分享知识的平台。
作为一名Web开发爱好者,我决定从零开始构建这个博客网站,而不是依赖现成的博客平台或内容管理系统,
这个过程充满了挑战和收获。🚀
本文目标
本文将详细介绍这个博客的技术栈、架构设计、核心JavaScript功能实现以及部署方案。
无论你是Web开发新手还是有经验的开发者,希望这篇文章能为你提供一些启发,
帮助你理解如何构建一个功能完善且个性化的静态博客网站。📝
核心理念
与使用WordPress或其他CMS相比,从零构建博客的优势在于完全掌控网站的各个方面,
从性能优化到用户体验设计,同时也是提升前端开发技能的绝佳机会。
正如我在设计这个博客时所遵循的理念:"简洁、高效、个性化"。💡
二、技术栈
2.1 核心技术
前端三件套
这个博客采用了纯前端技术栈构建,不依赖任何后端服务或数据库,完全由静态文件组成。
这种架构具有部署简单、加载迅速的优势。⚡
技术选择详解
具体技术选择及其优势:
- HTML5 - 语义化标签提升了网站结构清晰度和SEO表现
- CSS3 - 自定义变量、Flexbox和Grid布局、媒体查询实现响应式设计
- 原生JavaScript - 不依赖任何框架,实现主题切换、语言国际化、动态内容加载等功能
2.2 外部库
精选辅助库
虽然尽量减少外部依赖,但为了增强特定功能和用户体验,我选择了几个轻量级库:📚
- Font Awesome - 提供丰富的图标集
- Google Fonts - 引入多种精美字体,如SF Pro Display(主字体)、Chewy和ZCOOL KuaiLe(特殊标题)
- Highlight.js - 代码高亮功能
引入方式
外部库引用示例:
<!-- 外部库引用示例 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/atom-one-light.min.css">
<link href="https://fonts.googleapis.com/css2?family=SF+Pro+Display:wght@300;400;500;600&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Chewy&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=ZCOOL+KuaiLe&display=swap" rel="stylesheet">
2.3 开发工具
工具链
开发过程中使用的工具:🛠️
- Visual Studio Code - 主要代码编辑器,配置了HTML/CSS/JS插件增强开发体验
- Git & GitHub - 版本控制和代码托管,同时也用于网站部署
- Browser DevTools - 调试和优化网站性能、响应式设计测试
- Lighthouse - 网站性能、可访问性、SEO和最佳实践评估
技术栈选择理由
对于个人博客项目,我优先考虑了以下因素:💭
- 简洁高效:无需复杂的构建流程和依赖管理
- 长期可维护:使用基础且经典的技术,降低技术债务
- 学习价值:深入理解Web基础,提升原生JavaScript编程能力
- 性能优先:轻量级技术栈确保网站加载速度快
- 部署便捷:静态网站可以轻松部署在任何托管服务上
三、网站架构
3.1 文件结构
组织原则
博客采用了模块化的文件结构,按功能和类型组织文件,便于维护和扩展:📂
healthjianblog/
├── index.html # 网站首页
├── css/ # 样式文件目录
│ ├── style.css # 全局样式
│ ├── dark-mode.css # 暗黑模式样式
│ ├── blog.css # 博客列表样式
│ ├── blog-post.css # 博客文章页样式
│ └── ... # 其他样式文件
├── js/ # JavaScript文件目录
│ ├── main.js # 主要功能
│ ├── theme.js # 主题切换功能
│ ├── language.js # 语言切换功能
│ ├── blog.js # 博客相关功能
│ └── ... # 其他功能模块
├── images/ # 图片资源目录
├── pages/ # 页面目录
│ ├── blog.html # 博客列表页
│ ├── about.html # 关于页面
│ ├── links.html # 链接页面
│ ├── project/ # 项目展示页目录
│ │ ├── project.html # 项目列表页
│ │ └── ... # 项目详情页
│ └── blog/ # 博客文章目录
│ ├── tech/ # 技术类文章
│ ├── life/ # 生活类文章
│ └── thoughts/ # 随想类文章
└── README.md # 项目说明
结构优势
这种组织方式有以下优点:
- 清晰的资源分类,易于查找和管理
- 模块化的JavaScript和CSS文件,有利于代码复用
- 文章按主题分类,简化内容管理
- 直观的目录结构,易于新成员理解项目
3.2 设计理念
核心设计原则
博客设计遵循以下核心理念:🎨
- 内容为王 - 简洁的设计突出内容本身,避免过多视觉干扰
- 用户体验优先 - 直观的导航、合理的布局、舒适的阅读体验
- 响应式设计 - 适配从手机到桌面的各种设备尺寸
- 可访问性 - 考虑色彩对比度、键盘导航等无障碍设计
- 性能优化 - 资源按需加载、图片优化、代码精简
3.3 组件结构
无框架组件化
虽然没有使用前端框架,但博客仍然采用了"组件化"的思想来组织HTML结构,每个页面主要分为以下几个组件:🧩
- 导航栏(Navbar) - 包含logo、菜单、社交图标和主题/语言切换按钮
- 页面内容(Main Content) - 根据页面类型展示不同内容
- 页脚(Footer) - 包含版权信息、联系方式和快速导航链接
文章页组件
对于博客文章页,还包含:
- 侧边栏(Sidebar) - 展示目录、文章元信息和导航
- 文章内容(Article) - 包含标题、正文和结语
- 评论区(Comments) - 允许读者互动
3.4 多语言支持
双语实现策略
博客实现了中英双语支持,采用了以下策略:🌐
- 使用HTML数据属性(data-en和data-zh)存储不同语言的文本
- 创建.bilingual-content容器包裹需要双语显示的长文本内容
- 通过添加/移除body上的CSS类(en/zh)控制当前语言显示
- 使用localStorage存储用户语言偏好
代码实现
双语支持的HTML结构示例:
<!-- 简短文本的双语实现 -->
<h2 data-en="About Me" data-zh="关于我">关于我</h2>
<!-- 长文本的双语实现 -->
<div class="bilingual-content">
<p class="zh-content">这是中文内容</p>
<p class="en-content" style="display: none;">This is English content</p>
</div>
四、JavaScript实现
4.1 主题切换功能
功能描述
博客实现了亮色/暗色主题切换功能,核心实现包括:🌓
- 使用CSS变量定义不同主题的颜色方案
- 通过在body上切换CSS类(light-mode/dark-mode)实现主题转换
- 使用localStorage存储用户主题偏好
- 根据当前时间自动选择默认主题(白天/黑夜)
核心代码
主题切换功能的JavaScript实现:
// 根据当前时间获取合适的主题
function getThemeByTime() {
const hour = new Date().getHours();
// 6:00-18:00 为日间模式,19:00-5:00 为夜间模式
return (hour >= 6 && hour <= 18) ? 'light-mode' : 'dark-mode';
}
// 检查用户之前的主题偏好
function checkThemePreference() {
const savedTheme = localStorage.getItem('theme');
// 如果用户手动设置了主题,优先使用
if (savedTheme) {
document.body.className = savedTheme;
updateThemeToggleIcon(savedTheme);
}
// 如果没有手动设置,根据时间自动判断
else {
const timeBasedTheme = getThemeByTime();
document.body.className = timeBasedTheme;
updateThemeToggleIcon(timeBasedTheme);
}
}
// 切换主题
function toggleTheme() {
if (document.body.classList.contains('dark-mode')) {
document.body.classList.remove('dark-mode');
document.body.classList.add('light-mode');
localStorage.setItem('theme', 'light-mode');
updateThemeToggleIcon('light-mode');
} else {
document.body.classList.remove('light-mode');
document.body.classList.add('dark-mode');
localStorage.setItem('theme', 'dark-mode');
updateThemeToggleIcon('dark-mode');
}
}
4.2 语言切换功能
多语言实现
博客的多语言实现原理:🔄
- 通过在body上切换CSS类(en/zh)控制当前语言
- 使用数据属性存储双语文本
- 针对更长的内容,使用带有显示/隐藏控制的容器元素
- 使用localStorage保存用户语言偏好
核心实现
语言切换的JavaScript函数:
// 更新所有带有语言属性的元素
function updateAllLanguageElements(lang) {
const elements = document.querySelectorAll('[data-en][data-zh]');
elements.forEach(element => {
element.textContent = element.getAttribute(`data-${lang}`);
});
// 更新搜索框占位符
const searchInputs = document.querySelectorAll('input[data-en-placeholder][data-zh-placeholder]');
searchInputs.forEach(input => {
input.placeholder = input.getAttribute(`data-${lang}-placeholder`);
});
// 更新长文本内容的显示/隐藏
const zhContents = document.querySelectorAll('.zh-content');
const enContents = document.querySelectorAll('.en-content');
if (lang === 'zh') {
zhContents.forEach(el => el.style.display = 'block');
enContents.forEach(el => el.style.display = 'none');
} else {
zhContents.forEach(el => el.style.display = 'none');
enContents.forEach(el => el.style.display = 'block');
}
}
4.3 动态内容加载
动态加载优势
博客列表页使用JavaScript动态加载文章内容,这种方式相比于静态HTML有以下优势:🔄
- 更容易实现文章过滤、搜索和分页功能
- 便于将来扩展,比如从API或JSON文件加载内容
- 避免重复的HTML代码,提高维护效率
实现示例
博客文章数据和加载函数:
// 博客文章数据示例
const blogPosts = [
{
id: 1,
title: { zh: "从零构建个人博客:技术栈与架构详解", en: "Building a Personal Blog from Scratch: Tech Stack and Architecture" },
excerpt: { zh: "详细介绍个人博客的技术栈、架构设计和核心功能实现...", en: "Detailed introduction to the tech stack, architecture design, and core functionality implementation of a personal blog..." },
date: "2025-04-25",
category: "tech",
tags: ["web-development", "frontend", "html-css-js"],
url: "blog/tech/blog-building.html"
},
// 更多文章...
];
// 加载特定页面的文章
function loadPagePosts(page, filter = 'all') {
const postsPerPage = 6;
const startIndex = (page - 1) * postsPerPage;
const endIndex = startIndex + postsPerPage;
// 根据筛选条件过滤文章
let filteredPosts = blogPosts;
if (filter !== 'all') {
filteredPosts = blogPosts.filter(post => post.tags.includes(filter) || post.category === filter);
}
const currentPosts = filteredPosts.slice(startIndex, endIndex);
const blogList = document.querySelector('.blog-list');
blogList.innerHTML = '';
// 当前语言
const currentLang = document.body.classList.contains('en') ? 'en' : 'zh';
// 生成文章卡片HTML
currentPosts.forEach(post => {
const postElement = document.createElement('article');
postElement.className = 'blog-post';
postElement.innerHTML = `
${post.title[currentLang]}
${post.excerpt[currentLang]}
`;
blogList.appendChild(postElement);
});
// 更新分页状态
updatePagination(page, Math.ceil(filteredPosts.length / postsPerPage));
}
4.4 性能优化技巧
优化策略
在JavaScript实现中采用了多种性能优化措施:⚡
- 事件委托 - 减少事件监听器数量,提高性能
- 防抖与节流 - 优化频繁触发的事件处理(如搜索、滚动)
- 异步加载 - 非关键资源延迟加载
- 代码模块化 - 按需加载不同功能模块
- 缓存DOM查询 - 避免重复查询DOM元素
防抖示例
防抖函数和搜索优化实现:
// 防抖函数实现
function debounce(func, delay) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
// 博客搜索实现(带防抖)
document.addEventListener('DOMContentLoaded', function() {
const searchInput = document.querySelector('.blog-search input');
// 使用防抖优化搜索,避免每输入一个字符就触发搜索
const debouncedSearch = debounce(function() {
const searchTerm = this.value.toLowerCase().trim();
performSearch(searchTerm);
}, 300);
if (searchInput) {
searchInput.addEventListener('input', debouncedSearch);
}
});
五、部署方案
5.1 部署选项
可选部署平台
作为一个纯静态网站,这个博客有多种部署选择:🚀
- GitHub Pages - 免费且集成Git工作流,是个人博客的理想选择
- Netlify - 提供持续部署、自定义域名和HTTPS支持
- Vercel - 针对前端项目优化,提供全球CDN加速
- 传统Web主机 - 通过FTP上传静态文件
- 云存储服务 - 如阿里云OSS、腾讯云COS、AWS S3等
5.2 GitHub Pages部署
部署流程
我选择使用GitHub Pages作为主要部署平台,部署流程如下:🔄
- 创建名为
username.github.io
的GitHub仓库(其中username是你的GitHub用户名) - 将本地代码推送到该仓库
- 在仓库设置中启用GitHub Pages
- (可选)配置自定义域名并设置HTTPS
部署命令
GitHub Pages部署的Git命令示例:
# 初始化Git仓库(如果尚未初始化)
git init
# 添加所有文件到Git
git add .
# 提交更改
git commit -m "Initial commit for blog deployment"
# 添加GitHub远程仓库
git remote add origin https://github.com/username/username.github.io.git
# 推送代码到主分支
git push -u origin main
5.3 CI/CD实现
自动化部署
为了简化更新流程,我设置了基本的CI/CD流水线:⚙️
- 使用GitHub Actions自动部署变更
- 配置简单的检查确保HTML、CSS和JavaScript文件的质量
- 实现自动化测试,验证网站各个页面是否正常加载
工作流配置
GitHub Actions工作流示例:
# GitHub Actions工作流示例 (.github/workflows/deploy.yml)
name: Deploy to GitHub Pages
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Validate HTML
run: |
npx html-validate "**/*.html"
- name: Deploy
uses: JamesIves/github-pages-deploy-action@4.1.4
with:
branch: gh-pages
folder: .
5.4 性能监控
监控工具
部署后,我使用以下工具监控网站性能:📊
- Google Analytics - 分析访问流量和用户行为
- Google Search Console - 监控搜索引擎索引状态
- Lighthouse - 定期检查性能、可访问性和SEO得分
- PageSpeed Insights - 分析并优化页面加载速度
持续优化
基于监控结果,持续进行优化调整,包括:🔧
- 优化图片尺寸和格式(如使用WebP)
- 实现图片懒加载
- 根据用户访问数据调整内容组织
- 优化关键渲染路径,提高首屏加载速度
结语
学习收获
从零构建个人博客是一次宝贵的学习经历,它不仅强化了我对Web基础技术的理解,
也让我深入思考用户体验、性能优化和可访问性等重要方面。
通过这个项目,我实践了"简洁高效"的设计理念,打造了一个既满足功能需求又具备个性化特色的博客平台。🎓
技术总结
这个博客采用纯静态设计,优先考虑内容展示和用户体验,
同时通过模块化的JavaScript实现了主题切换、多语言支持和动态内容加载等特性。
部署在GitHub Pages上,既节省了成本,又简化了维护流程。💻
实用建议
对于有兴趣构建自己博客的读者,我的建议是:从简单开始,专注于内容而不是复杂的技术栈;
逐步迭代,根据实际需求添加功能;重视性能和用户体验,它们往往比华丽的效果更重要。💡
核心理念
最后,博客的核心永远是内容。技术只是展示内容的工具,真正吸引读者的是有价值、有见解的文章。
希望这篇技术分享能对你有所启发,欢迎在评论区交流你的想法和经验! 💻✨
— HealthJian ✍️
评论
成为第一个评论的人! 🎉