Litao

这个站点是怎么搭的

How This Site Is Built

这个站点是 Jekyll 生成的静态页面,托管在 GitHub Pages 上,由 GitHub Actions 构建。整站没有任何服务端逻辑。域名走 Cloudflare,访问统计用的是 Cloudflare Web Analytics——它由边缘节点注入,仓库里没有相关代码,也不使用 cookie,只记录页面维度的访问量。写作流程是在编辑器里写 Markdown,git push,GitHub 自动构建并发布。

暂时不做评论区。理由不是技术上做不到,而是我想先把写作本身跑顺。多媒体内容一律外链——视频挂在别的平台,大文件放 Releases,站点本身只有文字和少量压缩过的图片。这样加载快,也不会因为某个第三方服务停摆而坏掉。

正文用 Source Serif 4 配思源宋体系统,两者本是同一设计体系,中英混排时横竖笔画的粗细能对上。中文段落两端对齐,西文段落左对齐——汉字等宽,两端对齐不会出现西文那种断裂的空隙。

想订阅的话,页脚有 RSS。

下面是完整的搭建和日常维护记录。原先散在几个文档里,现在归到一处。

从零建一个

仓库命名。 新建一个公开仓库,名字必须严格是 你的用户名.github.io——用户名是 litao,仓库名就得是 litao.github.io。这是 GitHub 识别「个人主站」的唯一命名方式,差一个字符都不行。

上传文件。 把项目全部文件放进仓库根目录。网页上传走「Add file → Upload files」;命令行:

git init
git add .
git commit -m "初始站点"
git branch -M main
git remote add origin https://github.com/你的用户名/你的用户名.github.io.git
git push -u origin main

打开 Pages。 仓库 → Settings → Pages,Source 选 GitHub Actions——不是默认的 Deploy from a branch。选错的话 GitHub 会用它自己那个冻结在 Jekyll 3.9 的经典构建,仓库里的 _plugins/ 不会被加载,图片会 404。

之后 .github/workflows/build.yml 接手构建。推送到 main 后在仓库的 Actions 页面能看到进度,一两分钟后站点更新。

配置

_config.yml 顶部那几个字段是唯一需要动的地方:

  • title / title_en——你的名字。两者相同时,英文那行会自动隐藏。
  • tagline / tagline_en——首页正中的定位语,中英各一行。
  • email——页脚的联系邮箱。
  • url——https://你的用户名.github.io。

然后把 about.md 里的占位内容换成自己的介绍。改完 _config.yml 要重新推送才生效。

日常写作

文件命名。 在 _posts/ 下新建文件,名字必须是 年-月-日-英文短名.md。命名或日期格式不对,文章不会显示——这是最常见的「我明明推上去了怎么没有」的原因。

Front matter 模板:

---
title: "中文标题"
title_en: "English Title"
summary: "首页列表里显示的一两句话。可以不写。"
date: 2026-09-15
lang: zh
---

正文从这里开始。

lang 填 zh 或 en,填 zh 会自动两端对齐。

常用元素。 脚注是正文里写 [^标签]、文末写 [^标签]: 内容,序号和位置自动排;引用块行首加 >。

图片压成 WebP 放进 assets/img/<文章文件名>/,一篇文章一个目录,全宽图控制在 100KB 以内,压缩用 Squoosh 就够。引用方式:

![说明](../assets/img/2026-08-22-colophon/文件名.webp)

开头那个 ../ 不是笔误。文章在 _posts/ 下、资源在 assets/ 下,所以在 Obsidian 这类编辑器里「上一级」正好是仓库根目录,这样写能直接预览出图。但线上文章的地址是 /2026/短名/,浏览器会把同一个相对路径解成 /2026/assets/img/...,404。所以 _plugins/obsidian_asset_paths.rb 在构建时把 HTML 属性里的 ../assets/ 改写成 /assets/——它只动 src= 和 href=,正文代码块里演示用的路径不会被误改。源文件里一律写 ../,两边都成立。

视频不要上传进仓库,嵌一个播放器:

<div class="embed">
<iframe src="https://www.youtube-nocookie.com/embed/视频ID" title="标题" loading="lazy" allowfullscreen></iframe>
</div>

.embed 会保持 16:9 比例,loading="lazy" 减少首屏压力。讲稿 PDF、数据集这类大文件放 GitHub Releases 或 Zenodo,文章里外链引用。

用 Obsidian 写

仓库本身就是一个 Obsidian 库:在 Obsidian 里选「打开文件夹作为库」,指向仓库根目录即可。.obsidian/ 下的配置跟着仓库走,已经设好四项——

  • 双链关掉。 Obsidian 默认写 [[双链]],Jekyll 不认。改成标准 Markdown 链接后,写出来的文件在任何地方都成立。
  • 链接用相对路径。 插图时自动写成 ../assets/img/...,正是上面那个约定。
  • 附件目录指向 assets/img。 截图直接粘进正文,文件自动落到这个目录,路径也自动写对,不用手改。想让附件按文章分目录,装社区插件 Custom Attachment Location,把附件路径设成 assets/img/${noteFileName},粘进来的图就落到 assets/img/<文章文件名>/ 下——插件目录不入库,得各自安装配置。
  • 新建文件落在 _posts/。

有一项要自己点:设置 → 核心插件 → 打开「模板」。模板目录已配成 _templates,新建文章后按插入模板,front matter 和当天日期就填好了。

文件名仍然必须是 年-月-日-英文短名——这是 Jekyll 的硬要求,Obsidian 不会帮你起。新建时直接这样命名,中文标题写在 front matter 的 title 里。想让文件名也自动生成,可以装社区插件 Templater,不装也不影响。

草稿不要放在 _posts/ 下。Jekyll 会把那里所有日期合规的文件都发出去。放 _drafts/(Jekyll 默认不发布),或者在 front matter 里写 published: false。

字体与本地预览

西文正文是 Source Serif 4,中文用系统宋体(Mac 上通常是 Songti SC)。Windows 下宋体屏显偏细,把 _config.yml 里的

typeface: serif

改成 sans,中文就切到黑体(苹方 / 思源黑体 / 微软雅黑)。

本地预览是可选的,不预览直接推上去看效果也行。要在本地跑:

bundle install
bundle exec jekyll serve --watch --livereload

然后访问 http://localhost:4000。改一下存一下,不到半秒重建并自动刷新——调样式时用这个循环,别靠推送看效果。

Gemfile 里用的是 Jekyll 4,不装 github-pages 那个 gem:它的作用是在本地模仿 Pages 经典构建那个冻结的环境,换成 Actions 之后就没意义了,去掉后依赖从 96 个 gem 降到 37 个。Gemfile.lock 不入库——不同机器的 Ruby 版本和 CPU 架构不同,锁文件反而会让 CI 装不上依赖。

几件需要记住的事

仓库是公开的,源文件对所有人可见,别提交私人内容。更要紧的是:Git 删除文件不会抹掉历史记录,敏感内容一旦提交过,就可能长期可见——发现提交错了,改文件是不够的。

容量上,站点上限约 1GB,月流量软限制约 100GB,所以媒体一律外链。

构建改成 GitHub Actions 之后,插件不再受 GitHub Pages 那份白名单限制,Jekyll 版本也由 Gemfile 说话——想加中文分词搜索、图片自动压缩、数学公式渲染,都不必再迁一次构建方式。代价是多了一个会失败的环节:构建挂了,那次改动就发不上去。不过线上还是上一个成功的版本,不会变成坏页面;仓库里那次提交旁边会出现红叉,点进去有完整日志。想加邮件订阅的话,在 _includes/footer.html 里放个表单就行,不影响现有结构。