How This Blog Was Built
The first post is about the blog itself — a write-up of every decision and step that went into putting this site together.
If you are setting up a similar lightweight developer blog with MkDocs Material, this should save you a couple of hours.
Why MkDocs Material?
I wanted three things:
- Write posts in Markdown — no CMS, no database, no WordPress.
- Deploy on every
git push— GitHub Actions builds the site and deploys to GitHub Pages. - Bilingual out of the box — English and Chinese, with search that handles both.
Static site generators are the obvious choice. Among them:
| Tool | Writing | i18n | Theme ecosystem |
|---|---|---|---|
| Hugo | Good | Built-in | Large, fragmented |
| Jekyll | Good | Plugins | GitHub Pages native |
| MkDocs Material | Good (Markdown) | Built-in search langs | One excellent theme |
MkDocs Material wins on the third column — one theme that does everything well, consistently,
without me stitching together five half-maintained templates. The blog plugin is
first-class, not an afterthought.
Step-by-step Setup
1. Scaffold
uv init
uv add mkdocs-material pillow cairosvg \
mkdocs-git-revision-date-localized-plugin \
mkdocs-rss-plugin
uv manages dependencies with a lockfile (uv.lock) so builds are reproducible.
After that,
mkdocs.yml and docs/index.md are the only files you touch. Replace index.md with your
landing page.
Local dev server:
2. Core Configuration
mkdocs.yml is the single source of truth. Here is what goes in:
# Blog plugin — posts, archive, categories, pagination
plugins:
- blog:
blog_dir: blog
post_dir: "{blog}/posts"
archive: true
categories: true
pagination: true
pagination_per_page: 10
authors_file: "{blog}/.authors.yml"
# Tags — auto-generates tag index pages
- tags
# Search with Chinese tokenization
- search:
lang: [en, zh]
# RSS
- rss:
match_path: blog/posts/.*
3. Bilingual Strategy
No separate site builds, no mkdocs-static-i18n plugin. Just a directory convention:
Search indexes both languages — the lang: [en, zh] line above tells the built-in segmenter to
handle CJK characters. Readers filter by language via the tag system.
4. GitHub Actions CI
A single workflow file (.github/workflows/ci.yml) does three things on every push to Master:
- Checkout the repo (full depth, needed for
git-revision-date-localized) pip installdependencies +mkdocs buildactions/deploy-pagesto publish
Set Settings → Pages → Source → GitHub Actions in the repo and you are done.
5. Analytics & Comments
Google Analytics 4 — one block in mkdocs.yml:
giscus — free, no-ads comment system powered by GitHub Discussions. Enable Discussions in the
repo settings, install the giscus app, and drop the repo/category IDs into mkdocs.yml.
6. Theme Polish — Atom One Dark Pro
This site doesn't use the stock Material palette.
Colors are inspired by Atom One Dark Pro -- I always like this palette, and was really sad when Atom stops updating 😿,
the popular VS Code theme. All overrides live in a single CSS file
(docs/stylesheets/extra.css) loaded via extra_css.
Dark mode (default):
| Variable | Hex | Usage |
|---|---|---|
| Background | #282c34 |
Page body |
| Surface | #21252b |
Code blocks, sidebar |
| Text | #abb2bf |
Body copy |
| Primary | #61afef |
Links, header |
| Accent | #56b6c2 |
Hover states |
Light mode:
| Variable | Hex | Usage |
|---|---|---|
| Background | #fafafa |
Page body |
| Surface | #ffffff |
Cards, sidebar |
| Text | #383a42 |
Body copy |
| Primary | #4078f2 |
Links, header |
| Accent | #0184bc |
Hover states |
Key CSS snippet:
[data-md-color-scheme="slate"] {
--md-default-bg-color: #282c34;
--md-primary-fg-color: #61afef;
--md-accent-fg-color: #56b6c2;
}
[data-md-color-scheme="default"] {
--md-default-bg-color: #fafafa;
--md-primary-fg-color: #4078f2;
--md-accent-fg-color: #0184bc;
}
The home page gets a hero layout — large title, single-line subtitle, and Material's
.md-button classes for CTA links. Blog post cards have rounded corners, subtle backgrounds,
and a hover lift effect. A fadeIn animation smooths page transitions.
Dark mode is set as the default — the slate palette entry is listed first in mkdocs.yml.
Writing a Post
Every post is a Markdown file with frontmatter:
---
date:
created: 2026-07-10
categories:
- en # language category: en or zh
- topic-name
tags:
- english # or chinese
- topic-tag
authors:
- requiema
---
# Title
Content goes here.
Drop it in docs/blog/posts/en/ or docs/blog/posts/zh/, commit, push — the CI pipeline handles
the rest.
Summary
| Dimension | Choice |
|---|---|
| SSG | MkDocs Material 9.7 |
| Hosting | GitHub Pages (Actions CI) |
| Language | en / zh via directory convention + tags |
| Search | Built-in, lang: [en, zh] |
| Analytics | Google Analytics 4 |
| Comments | giscus (GitHub Discussions) |
| RSS | mkdocs-rss-plugin |
| Writing | Markdown + YAML frontmatter |
The full config is in the repo source. Go write something.