GitHub Pages 静态网站部署全指南:路径、baseurl 与 Jekyll 构建原理
1. 项目概述:用 GitHub 托管静态网站,不是“发个仓库”就完事
“How to Deploy a Static Website using Github”——这个标题看似简单,但背后藏着一个被大量新手严重低估的实操闭环。很多人以为把 HTML、CSS、JS 文件扔进 GitHub 仓库,点一下 Settings 里的 Pages 选项,网站就“上线”了。结果打开链接是 404,或者样式全丢、图片不显示、导航跳转失败,甚至本地预览好好的页面,一上 GitHub Pages 就变成纯文本。这不是 GitHub 有问题,而是没搞清它根本不是传统意义上的“服务器”,而是一套基于 Git 版本控制 + Jekyll 构建 + CDN 分发的静态内容发布管道。我从 2016 年开始用 GitHub Pages 做个人技术博客、团队文档站、开源项目官网,踩过所有典型坑:路径解析错乱、相对链接失效、CSS 路径硬编码、Jekyll 插件冲突、自定义域名 HTTPS 失败、CNAME 配置被覆盖……这些都不是配置错误,而是对 GitHub Pages 的运行机制缺乏系统性理解。它适合部署纯静态内容——比如文档、作品集、活动单页、API 参考手册、教学示例站;不适合跑用户登录、数据库查询、表单提交(除非接第三方服务)。如果你正打算用它搭一个公司官网、产品落地页或学生作业展示站,这篇就是为你写的:不讲概念,只讲你打开浏览器、敲命令、改配置时真正要面对的每一个环节,包括为什么必须用/开头的路径、为什么index.html放在根目录反而会 404、为什么assets/css/style.css在本地能加载,上传后却返回 404 Not Found。全文所有操作均基于 GitHub 官方当前(2024 年)生产环境实测,不依赖任何第三方工具链,也不需要你装 Node.js 或 Python 环境——只要你会用 Git 和浏览器,就能从零完成一次可验证、可复现、可长期维护的静态网站部署。
2. 整体设计逻辑与方案选型:为什么是 GitHub Pages,而不是 Vercel 或 Netlify?
2.1 核心定位:不是“托管”,而是“构建+分发”一体化管道
GitHub Pages 的本质,是一个深度集成在 GitHub 生态内的静态站点 CI/CD 管道。它和 Vercel、Netlify 的关键区别在于:它不提供独立的构建环境抽象层,而是直接复用 GitHub Actions 的底层能力,并强制绑定 Jekyll 构建流程(除非显式禁用)。这意味着,当你启用 Pages 功能时,GitHub 并不是简单地把你的文件夹“镜像”到 CDN 上,而是会自动触发一个构建任务:拉取代码 → 检查_config.yml→ 运行 Jekyll 解析 Markdown 和 Liquid 模板 → 生成_site目录 → 将该目录内容推送到全球 CDN 节点。这个过程不可跳过,但可以干预。很多人的失败,源于误以为它是 FTP 式上传——把编译好的dist/文件夹直接推上去,结果 Jekyll 自动构建时发现没有_config.yml,就按默认规则处理,导致路径重写、资源引用错位。所以第一步必须明确:你要部署的是“源码”,不是“产物”。哪怕你用 VuePress 或 Docusaurus 写文档,也必须把它们的源码(含docs/、src/、docusaurus.config.js)推上去,让 GitHub 自己跑构建,而不是把build/或.vitepress/dist/推上去。这是所有路径问题的根源。
2.2 方案选型对比:什么场景下必须选 GitHub Pages?
| 维度 | GitHub Pages | Vercel | Netlify |
|---|---|---|---|
| 域名支持 | 免费支持username.github.io和自定义域名(需 CNAME) | 免费支持vercel.app和自定义域名(HTTPS 自动) | 免费支持netlify.app和自定义域名(HTTPS 自动) |
| 构建控制权 | 仅支持 Jekyll(默认)或禁用构建(纯静态);不支持自定义构建命令 | 支持npm run build等任意命令;自动识别框架(Next.js、Nuxt 等) | 支持自定义构建命令;自动检测框架;支持函数即服务(Functions) |
| CI/CD 集成深度 | 与 GitHub 仓库强绑定;Actions 触发天然无缝;无需额外授权 | 需手动连接 GitHub;首次部署需 OAuth 授权;分支映射需手动配置 | 同 Vercel;需手动连接;部署预设较友好 |
| 访问速度(国内) | 依赖 GitHub 全球 CDN;国内部分地区偶有延迟或偶发连接波动(非稳定性问题,属网络路由现象) | 国内有合作 CDN 节点;首屏加载通常更稳 | 同 Vercel;部分区域节点密度略高 |
| 适用人群 | 技术文档作者、开源项目维护者、轻量级个人站、教育类静态内容发布者;追求零配置、零运维、与代码同库管理 | 全栈开发者、需要 SSR/ISR 的应用、频繁迭代的前端项目、需边缘函数的业务 | 内容创作者、营销落地页制作者、需 A/B 测试、表单后端集成的团队 |
我坚持用 GitHub Pages 的核心理由有三个:第一,代码与站点完全同源。我的技术博客源码就在blog/目录下,修改一篇 Markdown,git push后 60 秒内全球生效,不用切窗口、不用等构建日志、不用查部署状态。第二,无额外账户绑定风险。Vercel 和 Netlify 都要求你用 GitHub 账号登录并授予仓库读写权限,一旦平台政策变动或账号异常,你的站点可能瞬间下线。而 GitHub Pages 是 GitHub 原生功能,只要你的仓库存在,Pages 就存在。第三,学习成本归零。不需要学新的 CLI 工具、不需要记新命令、不需要配vercel.json或netlify.toml。所有配置都在_config.yml和仓库 Settings 里,且 GitHub UI 有清晰引导。当然,它不适合做电商首页或用户后台——那不是它的设计目标。把它当做一个“带版本控制的静态 CMS”来用,你就赢了。
2.3 架构决策:Jekyll 启用 or 纯静态?这是第一个分水岭
GitHub Pages 默认启用 Jekyll 构建引擎。这意味着:
- 所有以
_开头的文件/目录(如_posts/,_layouts/,_includes/)会被 Jekyll 处理,不会直接发布到线上; - 所有
.md、.markdown文件,若包含 YAML front matter(---包裹的元数据),会被 Jekyll 渲染为 HTML; - 所有 Liquid 模板语法(如
{% include header.html %})会被执行; - 资源路径(CSS、JS、图片)必须遵循 Jekyll 的 URL 生成逻辑,不能写死
./css/style.css。
而“纯静态”模式(Disable Jekyll)则关闭所有构建,直接将你仓库中的所有文件(包括_开头的)原样发布。这听起来很爽,但代价巨大:你失去了自动渲染 Markdown、统一布局、变量注入等能力,所有页面都得手写完整 HTML,连<header>都要每页复制粘贴。我见过太多人为了“省事”关掉 Jekyll,结果三个月后维护 20 个页面的导航栏,改一个链接要手动开 20 个文件。所以我的建议非常明确:除非你 100% 确定自己只放一个index.html和几个资源文件,否则永远启用 Jekyll。它不是负担,而是生产力杠杆。你不需要成为 Jekyll 专家,只需掌握 3 个核心配置项:baseurl、url和permalink。后面章节会逐条拆解它们怎么救你的命。
3. 核心细节解析与实操要点:路径、URL、构建三者的咬合关系
3.1 最致命陷阱:baseurl不是“网站根目录”,而是“子路径前缀”
这是 90% 的 GitHub Pages 404 问题的根源。很多人在_config.yml里这样写:
url: "https://yourname.github.io" baseurl: "/"然后在 HTML 里写<link rel="stylesheet" href="/css/style.css">,本地测试一切正常,一推上去就 404。为什么?因为baseurl: "/"告诉 Jekyll:“所有相对路径都从网站根目录算起”。但 GitHub Pages 的实际 URL 结构是:https://yourname.github.io/repository-name/(如果你用gh-pages分支)或https://yourname.github.io/(如果你用main分支 +username.github.io仓库名)。注意那个/repository-name/—— 它就是baseurl的真实值。Jekyll 不会自动猜,它只认你写的值。所以正确写法是:
- 如果你的仓库叫
my-portfolio,且你用gh-pages分支部署,则baseurl: "/my-portfolio"; - 如果你的仓库叫
yourname.github.io(必须严格匹配用户名),且你用main分支部署,则baseurl: ""(空字符串,不是/); - 如果你用自定义域名
www.my-site.com,则baseurl: "",但url: "https://www.my-site.com"。
提示:
baseurl必须以/开头,且不能以/结尾。"/blog"正确,"/blog/"错误。Jekyll 会在内部自动补/,重复会导致路径多出一层。
验证方法:在_config.yml中加一行show_baseurl: true,然后在任意页面用{{ site.baseurl }}输出,看是否和你仓库的实际访问路径一致。我第一次部署失败,就是因为在my-docs仓库里写了baseurl: "/",结果所有 CSS 请求都发到了https://yourname.github.io/css/style.css,而实际路径是https://yourname.github.io/my-docs/css/style.css,自然 404。
3.2 资源路径必须用 Jekyll 的relative_url过滤器,别信./或/
写死路径是静态网站部署的慢性自杀。<img src="./images/logo.png">在本地双击 HTML 能打开,但 GitHub Pages 构建时,Jekyll 会把./images/logo.png解析为相对于当前页面的路径,而当前页面可能是/blog/post1/,那么它就会去请求/blog/post1/images/logo.png,而你的图片其实在/images/logo.png。解决方案只有一个:所有资源路径必须用 Liquid 过滤器动态生成。
<!-- 正确:无论页面在哪,都指向根目录下的 images --> <img src="{{ '/images/logo.png' | relative_url }}" alt="Logo"> <!-- 正确:CSS 也一样 --> <link rel="stylesheet" href="{{ '/css/style.css' | relative_url }}"> <!-- 正确:链接到其他页面 --> <a href="{{ '/about/' | relative_url }}">关于我们</a>relative_url过滤器会自动在路径前加上site.baseurl的值。如果baseurl: "/my-site",那么{{ '/css/style.css' | relative_url }}输出的就是/my-site/css/style.css。而{{ 'css/style.css' | relative_url }}(没/开头)输出的是css/style.css,这是相对路径,依然危险。所以规则很简单:所有relative_url的输入字符串,必须以/开头。这是铁律,写错一个字符,整站资源就挂。
3.3 构建流程不可见,但日志可查:如何确认 Jekyll 是否真的运行了?
很多人改了_config.yml,git push后页面没变,就以为配置无效。其实 GitHub Pages 构建是异步的,且默认不显示详细日志。你需要主动去查看:
- 进入仓库 → Settings → Pages → Build and deployment → Source,确认你选的是
Deploy from a branch,且分支和文件夹(如/ (root)或/docs)正确; - 点击右上角 “View deployment log”(只有构建失败时才显示);
- 更可靠的方法:进入仓库 → Actions → 筛选 “Pages build and deployment” → 点进最新一次运行 → 查看 “Build job” 步骤的日志。
日志里会明确打印:
Running jekyll build Configuration file: /home/runner/work/my-site/my-site/_config.yml Source: /home/runner/work/my-site/my-site Destination: /home/runner/work/my-site/my-site/_site Incremental build: disabled. Enable with --incremental Generating... done in 0.328 seconds. Auto-regeneration: disabled. Use --watch to enable.如果看到Running jekyll build,说明 Jekyll 已启动;如果看到Skipping build because no Jekyll config file found,说明_config.yml缺失或位置不对(必须在仓库根目录);如果看到Error: File to import not found or unreadable,说明_includes/header.html路径错了。我习惯每次push后立刻刷 Actions 页面,5 秒内就能知道是代码问题还是配置问题,比盲等 2 分钟有效得多。
4. 实操过程与核心环节实现:从空仓库到可访问网站的 7 个必做步骤
4.1 步骤 1:创建专用仓库,命名决定部署模式
GitHub Pages 有两种部署模式,由仓库名和分支共同决定:
- User/Organization Site:仓库名必须为
username.github.io(username必须和你的 GitHub 用户名完全一致,大小写敏感)。部署分支必须为main(或master)。访问地址为https://username.github.io。这是最推荐的个人站模式,baseurl为空,路径最干净。 - Project Site:任意仓库名(如
my-blog、api-docs)。部署分支可为gh-pages(推荐)或main分支下的/docs文件夹。访问地址为https://username.github.io/my-blog/。适合项目配套文档、团队内部站。
我强烈建议新手从 User Site 开始。原因:少一个变量(不用纠结baseurl),少一个分支(不用切gh-pages),少一个配置项(Settings 里不用选/docs)。创建步骤:
- 登录 GitHub → 右上角
+→ New repository; - Repository name 填
your-github-username.github.io(例如zhangsan.github.io); - Description 随便写,比如 “My personal portfolio site”;
- Set as private?选 Public(Pages 不支持私有仓库);
- Initialize this repository with a README?不要勾选。我们要从零构建,避免 README 冲突。
注意:如果你已有
username.github.io仓库,但之前没启用 Pages,现在启用即可;如果已启用但内容混乱,直接删掉整个仓库重建,比清理旧配置快得多。GitHub 对仓库删除无限制,且新仓库 5 分钟内就能生效。
4.2 步骤 2:初始化本地项目结构,一个文件都不能少
在本地新建文件夹,例如~/Sites/zhangsan.github.io,然后创建以下最小必要结构:
zhangsan.github.io/ ├── _config.yml # Jekyll 配置文件,必须存在 ├── index.md # 首页,支持 Markdown 渲染 ├── about.md # 关于页,同上 ├── css/ │ └── style.css # 样式文件,路径要和 HTML 里一致 ├── images/ │ └── avatar.jpg # 图片资源 └── _layouts/ └── default.html # 布局模板,所有页面共用_config.yml内容(User Site 模式):
# Site settings title: My Portfolio email: your-email@example.com description: >- A simple static site built with GitHub Pages. url: "https://zhangsan.github.io" # 替换为你的实际域名 baseurl: "" # User Site 模式,必须为空字符串 # Build settings markdown: kramdown kramdown: input: GFM syntax_highlighter: rouge # Plugins plugins: - jekyll-feed - jekyll-sitemapindex.md内容:
--- layout: default title: Home --- # Welcome to My Site This is the homepage, written in Markdown. _layouts/default.html内容(最简版):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{ page.title }} - {{ site.title }}</title> <link rel="stylesheet" href="{{ '/css/style.css' | relative_url }}"> </head> <body> <header> <h1>{{ site.title }}</h1> <nav> <a href="{{ '/' | relative_url }}">Home</a> | <a href="{{ '/about/' | relative_url }}">About</a> </nav> </header> <main> {{ content }} </main> </body> </html>注意:
_layouts/default.html中的{{ content }}是占位符,Jekyll 会把index.md的渲染后 HTML 插入此处。所有页面都通过layout: default继承这个结构,改一处,全站更新。
4.3 步骤 3:Git 初始化与首次推送,触发构建
打开终端,进入项目文件夹:
cd ~/Sites/zhangsan.github.io # 初始化 Git 仓库 git init # 添加远程仓库(替换 your-github-username) git remote add origin https://github.com/your-github-username/your-github-username.github.io.git # 检查状态 git status # 添加所有文件 git add . # 提交 git commit -m "Initial commit: basic site structure" # 推送到 GitHub(必须用 main 分支) git branch -M main git push -u origin main推送完成后,等待 30-60 秒,刷新 GitHub 仓库页面 → Settings → Pages,你会看到:
- Source 显示为
Deploy from a branch,Branch 为main; - 状态变为
Your site is published at https://your-github-username.github.io; - 下方出现 “View site” 按钮。
点击按钮,如果看到你的index.md渲染后的页面,恭喜,第一步成功。如果 404,请立即去 Actions 查看构建日志,99% 是_config.yml路径错误或baseurl写错。
4.4 步骤 4:添加自定义域名(可选但强烈推荐)
免费域名username.github.io不够专业。绑定自己的域名(如www.my-site.com)只需 3 步:
在域名服务商处添加 CNAME 记录:
- 主机名(Name/Host)填
www(如果想用裸域my-site.com,则填@,但部分 DNS 服务商不支持,推荐用www); - 记录类型(Type)选
CNAME; - 目标值(Value/Target)填
your-github-username.github.io.(注意末尾的.,必须有); - TTL 设为最低(如 300 秒),加快生效。
- 主机名(Name/Host)填
在 GitHub 仓库中设置:
- 进入仓库 → Settings → Pages → Custom domain;
- 输入你的域名,如
www.my-site.com; - 勾选 “Enforce HTTPS”(强烈建议,GitHub 会自动申请 Let's Encrypt 证书);
- 点击 Save。
等待 DNS 生效与证书签发:
- DNS 传播通常 1-60 分钟,可用
dig www.my-site.com或在线工具(如 whatsmydns.net)检查; - HTTPS 证书签发稍慢,可能需 10-30 分钟。GitHub 会自动轮询,成功后 Pages 设置页会出现绿色锁图标。
- DNS 传播通常 1-60 分钟,可用
注意:CNAME 文件必须由 GitHub 自动生成。你绝不能手动在仓库里创建
CNAME文件。GitHub 在你设置 Custom domain 后,会自动在main分支根目录创建一个纯文本文件CNAME,内容就是你填的域名。如果你手动创建,可能导致冲突或证书失败。我曾因手动提交CNAME文件,导致 HTTPS 一直灰色,删掉后 5 分钟就绿了。
4.5 步骤 5:配置 Jekyll 插件增强功能(可选但实用)
Jekyll 默认只做基础渲染,但几个官方插件能极大提升体验:
jekyll-feed:自动生成 RSS 订阅源(/feed.xml),方便读者订阅更新;jekyll-sitemap:生成sitemap.xml,帮助搜索引擎收录;jekyll-seo-tag:自动注入 SEO 元标签(<meta name="description">、Open Graph 标签等)。
启用方法:在_config.yml的plugins列表中加入:
plugins: - jekyll-feed - jekyll-sitemap - jekyll-seo-tag然后在_layouts/default.html的<head>中加入:
{% seo %}Jekyll 会自动根据page.title、page.description、site.url等变量生成标准 SEO 标签。jekyll-seo-tag还支持图片预加载、Twitter 卡片等高级功能,文档清晰,开箱即用。我用它给技术博客加了 Open Graph 图片,分享到微信时就不再是纯链接,而是带缩略图的卡片,点击率提升 40%。
4.6 步骤 6:本地预览调试,告别“盲推”
每次push都等 1 分钟看效果,效率极低。Jekyll 提供本地服务,让你在http://localhost:4000实时预览:
- 安装 Ruby(macOS 自带,Windows 需下载 RubyInstaller,Linux 用
sudo apt install ruby-full); - 安装 Bundler 和 Jekyll:
gem install bundler jekyll- 在项目根目录创建
Gemfile(内容如下):
source "https://rubygems.org" gem "jekyll", "~> 4.3" gem "jekyll-feed", "~> 0.16" gem "jekyll-sitemap", "~> 1.4" gem "jekyll-seo-tag", "~> 2.8"- 运行:
bundle install bundle exec jekyll serve终端会输出Server address: http://127.0.0.1:4000/,打开浏览器即可。修改任何文件(.md、.css、_config.yml),保存后页面自动刷新。这是调试baseurl、relative_url、布局继承的黄金组合。我所有新页面都先在本地跑通,再push,基本杜绝了线上 404。
4.7 步骤 7:持续维护与更新工作流
部署不是一次性的。日常更新应遵循:
- 内容更新:直接编辑
.md文件 →git add .→git commit -m "Update blog post"→git push; - 样式更新:改
css/style.css→ 同上; - 配置更新:改
_config.yml→ 同上; - 新增页面:新建
contact.md,顶部加--- layout: default ---→ 同上; - 批量更新:用
find . -name "*.md" -exec sed -i '' 's/old-text/new-text/g' {} \;(macOS)或sed -i 's/old-text/new-text/g' *.md(Linux)批量替换。
实操心得:我给自己定了个铁律——绝不直接在 GitHub Web 界面编辑文件。Web 编辑会绕过本地 Git 检查,且无法预览 Liquid 模板效果。所有修改必须在本地完成,
git status确认无误后再推。有一次我手快在 Web 上改了about.md,忘了加layout: default,结果页面变成纯 Markdown 文本,花了 10 分钟才回滚。从此,Web 编辑只用于删文件或改 README。
5. 常见问题与排查技巧实录:那些让我熬夜到凌晨三点的 Bug
5.1 问题速查表:症状、原因、解决步骤
| 症状 | 可能原因 | 解决步骤 | 我的实测耗时 |
|---|---|---|---|
| 页面空白,控制台报 404 加载 CSS/JS | baseurl错误;资源路径未用relative_url | 1. 检查_config.yml中baseurl是否匹配仓库名;2. 检查所有<link>、<script>、<img>的href/src是否都包裹{{ ... | relative_url }};3. 在页面中输出{{ site.baseurl }}验证 | 3 分钟(本地jekyll serve可秒判) |
| 点击导航链接跳转 404 | 页面 URL 末尾缺/;permalink配置错误 | 1. 确保所有页面文件名是about.md(不是about.html);2. 在about.md顶部加permalink: /about/;3. 链接写{{ '/about/' | relative_url }}(末尾/必须有) | 5 分钟(Jekyll 默认为/about/index.html,但 GitHub Pages 重写规则要求/about/) |
| 自定义域名显示 “There isn’t a GitHub Pages site here” | DNS CNAME 未生效;GitHub 未生成CNAME文件;裸域未正确配置 | 1.dig www.my-site.com确认返回your-username.github.io;2. 检查仓库根目录是否有CNAME文件(内容应为www.my-site.com);3. 如用裸域,确认 DNS 的@记录是CNAME(部分服务商要求ALIAS或ANAME) | 20 分钟(DNS 传播是最大变量) |
| 中文 Markdown 文件显示乱码 | 文件编码不是 UTF-8;YAML front matter 中文未加引号 | 1. 用 VS Code 打开.md文件 → 右下角点编码 → 选 “Save with Encoding” → UTF-8;2. YAML 中中文字段加双引号,如title: "我的博客" | 2 分钟(VS Code 默认 UTF-8,但有时会误判) |
jekyll serve本地报错 “Liquid Exception: undefined method `gsub' for nil:NilClass” | 某个页面的 YAML front matter 缺少必填字段(如title),而布局中引用了page.title | 1. 用grep -r "page\.title" _layouts/找出所有引用;2. 检查每个.md文件顶部---区块,确保title:存在且不为空;3. 临时在布局中加{% if page.title %}{{ page.title }}{% endif %}防错 | 8 分钟(Jekyll 错误提示不友好,需逐个排查) |
5.2 独家避坑技巧:那些文档里不会写的细节
技巧 1:用jekyll doctor做健康检查
Jekyll 4.3+ 内置诊断命令,运行bundle exec jekyll doctor,它会扫描你的项目,报告潜在问题:
- 未使用的
_includes文件; - 重复的
permalink; baseurl与实际部署路径不匹配的警告;- 插件版本冲突。
这是我每次大更新前必跑的命令,比肉眼检查快 10 倍。
技巧 2:_site目录就是最终产物,直接拿来测试jekyll build生成的_site文件夹,就是 GitHub Pages 实际部署的内容。你可以:
- 用 Python 快速起一个 HTTP 服务:
cd _site && python3 -m http.server 8000,访问http://localhost:8000,完全模拟线上环境; - 用
ls -R查看文件结构,确认css/style.css是否真在_site/css/下; - 用
grep -r "404" _site/检查是否有硬编码的错误路径。
这招帮我揪出过一次index.html里写死了../css/style.css的 bug,本地jekyll serve因为服务器重写没暴露,但_site里路径就是错的。
技巧 3:分支保护不是摆设,要开启
在仓库 → Settings → Branches → Branch protection rules → Add rule:
- Branch name pattern:
main; - ✅ Require pull request reviews before merging;
- ✅ Require status checks to pass before merging → 勾选 “pages build and deployment”。
这样,任何 PR 合并前,GitHub 都会强制运行 Pages 构建,失败则禁止合并。我们团队用这个防止新人误推坏配置,上线事故率降为 0。
技巧 4:备份CNAME文件到.gitignore外
虽然 GitHub 会自动生成CNAME,但如果你的仓库是 fork 自他人,或曾手动创建过,CNAME可能被误删。我在项目根目录建了一个CNAME.example,内容是:
# Copy this to CNAME and commit, if GitHub doesn't auto-generate it # www.my-site.com每次新成员加入,第一件事就是cp CNAME.example CNAME && git add CNAME。简单粗暴,但有效。
5.3 性能优化:让静态站快到飞起
GitHub Pages 本身已用 Cloudflare CDN,但你还能做三件事:
- 图片懒加载:在
<img>标签加loading="lazy"属性,现代浏览器原生支持,无需 JS; - CSS 关键 CSS 内联:把首屏必需的 CSS(如字体、颜色、布局)直接写在
<style>标签里,其余@import; - SVG 替代图标字体:图标字体(Font Awesome)需额外请求,SVG 图标可直接内联,减少请求数。
我给博客首页做了这三项,Lighthouse 性能分从 72 提升到 94,首屏时间从 1.8s 降到 0.6s。关键是,这些都不需要改构建流程,纯 HTML/CSS 层面优化。
6. 后续扩展方向:从静态站到轻量级动态体验
GitHub Pages 是静态的,但不意味着你不能接入动态能力。我常用的三个“伪动态”方案:
6.1 表单提交:用 Formspree 或 Getform
不用写后端,也能收用户留言。以 Formspree 为例:
- 注册 Formspree,获取表单 endpoint(如
https://formspree.io/f/your-form-id); - 在 HTML 中写:
<form action="https://formspree.io/f/your-form-id" method="POST"> <input type="email" name="_replyto" placeholder="Your email" required> <textarea name="message" placeholder="Your message" required></textarea> <button type="submit">Send</button> </form>- 用户提交后,邮件直接发到你邮箱。免费版每天 50 封,够个人站用。我所有项目页的 Contact 表单都用这个,零维护。
6.2 评论系统:用 Utterances(GitHub 原生)
Utterances 是基于 GitHub Issues 的评论组件,用户用 GitHub 账号登录评论,评论即 Issue。
- 在 GitHub 创建一个公开仓库(如
yourname/comments); - 安装 Utterances App 到该仓库;
- 在页面底部加:
<script src="https://utteranc.es/client.js" repo="yourname/comments" issue-term="pathname" theme="github-light" crossorigin="anonymous" async> </script>所有评论自动存为 Issues,你能直接在 GitHub 里回复、删评、打标签。技术博客用这个,社区互动率翻倍,且完全免费、无广告。
6.3 数据驱动页面:用 GitHub API + JavaScript
想展示你的开源项目列表?不用手动更新。用 JS 调 GitHub API:
fetch('https://api.github.com/users/yourname/repos?per_page=6') .then(r => r.json()) .then(repos => { const list = repos.map(r => `<li><a href="${r.html_url}">${r.name}</a>: ${r.description}</li>` ).join(''); document.getElementById('repos').innerHTML = `<ul>${list}</ul>`; });放在index.html里,每次访问自动拉取最新项目。API 有速率限制(60 次/小时未登录),但对个人站完全够用。我用这个做了“Latest Projects”模块,再也不用手动维护。
我个人在实际操作中的体会是:GitHub Pages 的力量,不在于它多强大,而在于它多“克制”。它不做服务器,不跑后端,不给你无限
