From fc850cd651b656fd65d7e04e5be55f31c696284d Mon Sep 17 00:00:00 2001 From: Vaica <94612053+zqlit@users.noreply.github.com> Date: Fri, 5 Jun 2026 13:58:26 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BD=A0=E6=9D=A5=E5=95=A6?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E6=96=87=E4=BB=B6txt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/博客字体优化文章规划.md | 354 +++++++++++++++++++ static/nilaila-verify.txt | 1 + write/.recycle/meta/202606041002.json | 7 + write/.recycle/posts/202606041002/index.md | 378 +++++++++++++++++++++ 4 files changed, 740 insertions(+) create mode 100644 docs/博客字体优化文章规划.md create mode 100644 static/nilaila-verify.txt create mode 100644 write/.recycle/meta/202606041002.json create mode 100644 write/.recycle/posts/202606041002/index.md diff --git a/docs/博客字体优化文章规划.md b/docs/博客字体优化文章规划.md new file mode 100644 index 00000000..f658f300 --- /dev/null +++ b/docs/博客字体优化文章规划.md @@ -0,0 +1,354 @@ +# 博客字体优化方案 - 文章规划 + +## 📋 文章定位 + +- **目标读者:** 生活博主、非技术背景博主 +- **文章风格:** 通俗易懂、重效果、少术语 +- **核心卖点:** 用真实案例告诉你,字体优化能让博客快多少 + +--- + +## 📝 推荐文章结构 + +### 标题建议(选一个) + +1. **我的博客加载快了50%,只因为改了字体** +2. **博客太慢?可能是字体拖后腿了** +3. **从3秒到1秒:我是怎么优化博客字体的** +4. **博客字体优化:一个让网站变快的简单技巧** + +**推荐:** 第1个(有具体数字,有悬念) + +--- + +### 文章大纲 + +``` +一、开头:我的博客有多慢?(引入问题) +二、发现问题:原来是字体拖后腿(诊断过程) +三、字体优化到底是什么?(通俗解释) +四、我是怎么做的(真实案例) +五、效果对比(数据说话) +六、你也可以这样做(通用方案) +七、总结 +``` + +--- + +## 📝 详细内容规划 + +### 一、开头:我的博客有多慢?(200字) + +**写法:** 从用户视角出发,描述痛点 + +**要点:** +- 博客打开要3秒以上 +- 移动端更慢,用户等不及就走了 +- 用了各种缓存、CDN都没用 +- 最后发现是字体文件太大 + +**示例段落:** +> 我的博客一直有个问题:打开太慢。 +> +> 用PageSpeed Insights测了一下,移动端得分只有60分。加载时间3秒多,这在现在这个"3秒定生死"的时代,基本等于告诉用户"别等了,走吧"。 +> +> 我试过开CDN、压缩图片、用缓存插件,效果都不明显。直到有一天,我在Network面板里发现了一个1.2MB的字体文件... + +--- + +### 二、发现问题:原来是字体拖后腿(300字) + +**写法:** 用通俗语言解释问题 + +**要点:** +- 中文字体为什么这么大?(2万个字符) +- 你的博客实际用了多少字?(可能只有2000个) +- 浪费了90%的带宽在不需要的字上 + +**类比:** +> 这就好比你要寄一封信,但邮局让你把整本字典一起寄出去。你只用了里面的几十个字,却要为整本字典的重量买单。 + +**数据展示:** +``` +原始字体:1,226 KB(包含20,000+字符) +实际使用:2,485字符 +浪费:90%的字符从未出现过 +``` + +--- + +### 三、字体优化到底是什么?(200字) + +**写法:** 用比喻解释,避免术语 + +**核心概念:** +- 字体子集化:只保留你用到的字 +- 就像"按需定制",不是"全买" + +**比喻:** +> 字体优化就像是去餐厅点菜。 +> +> 原来的方式:把整本菜单都买下来,只吃其中几道。 +> 优化后的方式:只点你要吃的菜,吃完走人。 +> +> 结果:花更少的钱,吃得一样饱。 + +**技术原理(简化版):** +1. 扫描你博客的所有文章 +2. 提取实际使用的字符 +3. 生成一个"精简版"字体 +4. 体积减少80%+ + +--- + +### 四、我是怎么做的(真实案例)(500字) + +**写法:** 分步骤讲解,附代码和截图 + +**步骤1:分析现状** +``` +工具:Chrome DevTools → Network面板 +发现:zql-v2.woff2 文件大小 1.2MB +``` + +**步骤2:选择工具** +- 推荐:Python + fonttools +- 备选:在线工具(无需编程) + +**步骤3:提取字符** +```bash +# 运行脚本,自动提取 +python subset-font.py +``` + +**步骤4:生成子集** +``` +结果: +- 原始:1,226 KB → 子集:740 KB +- 减少:40% +``` + +**步骤5:更新CSS** +```css +/* 修改前 */ +src: url('../font/zql-v2.woff2'); + +/* 修改后 */ +src: url('../font/zql-v2-subset.woff2'); +``` + +**截图建议:** +1. Network面板显示字体大小对比 +2. 脚本运行结果截图 +3. 优化前后文件大小对比 + +--- + +### 五、效果对比(数据说话)(300字) + +**写法:** 用图表和数据展示效果 + +**数据表格:** + +| 指标 | 优化前 | 优化后 | 提升 | +|------|--------|--------|------| +| 字体大小 | 1.2 MB | 740 KB | -40% | +| 加载时间 | 3.2秒 | 1.8秒 | -44% | +| PageSpeed得分 | 60 | 85 | +42% | +| 移动端体验 | 差 | 良好 | ✅ | + +**用户体感:** +> 优化后最明显的变化是:页面"刷"一下就出来了。 +> +> 以前打开文章,能明显看到文字先显示为方块,然后才变成正常字体。现在几乎看不到这个过程了。 + +**截图建议:** +1. PageSpeed Insights优化前后对比 +2. Network面板加载瀑布图 +3. 实际打开速度对比GIF + +--- + +### 六、你也可以这样做(通用方案)(400字) + +**写法:** 提供可复用的方案 + +**方案A:在线工具(零代码)** +1. 访问 fontsquirrel.com/webfont-generator +2. 上传你的字体文件 +3. 选择"Expert"模式 +4. 勾选"Custom Subsetting" +5. 下载优化后的字体 +6. 替换原文件,更新CSS + +**方案B:Python脚本(推荐)** +```bash +# 安装工具 +pip install fonttools brotli + +# 运行脚本 +python subset-font.py +``` + +**方案C:找我帮忙(最简单)** +- 提供你的博客地址 +- 我帮你分析和优化 +- 全程指导,保证效果 + +**注意事项:** +- 优化前备份原文件 +- 测试所有页面的显示效果 +- 特殊符号可能需要单独处理 + +--- + +### 七、总结(150字) + +**要点回顾:** +1. 中文字体很大,但你用的字很少 +2. 字体优化可以减少40-90%的大小 +3. 加载速度提升明显 +4. 操作并不复杂 + +**结尾金句:** +> 博客优化就像减肥:找对方法,效果立竿见影。 +> +> 字体优化就是那个你一直忽略、但效果惊人的"减肥方法"。 +> +> 试试看,你的博客也能快50%。 + +--- + +## 📊 文章数据 + +### 预期指标 +- **字数:** 2000-2500字 +- **阅读时间:** 8-10分钟 +- **代码块:** 5-6个(简化版) +- **截图:** 8-10张 +- **表格:** 2-3个 + +### SEO关键词 +- 博客优化 +- 字体优化 +- 网站加速 +- Hugo优化 +- 字体子集化 +- PageSpeed提升 + +--- + +## 🎨 排版建议 + +### 标题层级 +- H2:大章节(7个) +- H3:小节(每章节2-3个) +- H4:更细的点(少用) + +### 视觉元素 +- ✅ 数据表格(对比效果) +- ✅ 代码块(简化版,带注释) +- ✅ 截图(Network面板、PageSpeed) +- ✅ 比喻图(餐厅点菜的比喻) +- ✅ 对比图(优化前后) + +### 代码展示原则 +- 只展示必要的代码 +- 每行代码都有注释 +- 提供"复制即用"的版本 +- 避免大段代码块 + +--- + +## 📸 截图清单 + +### 必须截图 +1. [ ] PageSpeed Insights优化前得分 +2. [ ] PageSpeed Insights优化后得分 +3. [ ] Network面板字体文件大小 +4. [ ] 脚本运行结果 +5. [ ] 优化前后文件大小对比 + +### 建议截图 +6. [ ] 字体加载瀑布图 +7. [ ] 实际打开速度对比 +8. [ ] 移动端测试结果 + +--- + +## ✍️ 写作技巧 + +### 开头吸引人 +- 用具体数字("3秒"、"50%") +- 描述用户痛点("用户等不及就走了") +- 制造悬念("最后发现是...") + +### 中间讲清楚 +- 用比喻解释技术概念 +- 分步骤讲解,每步都清晰 +- 提供"复制即用"的代码 + +### 结尾有力量 +- 总结核心要点 +- 给出行动建议 +- 用金句收尾 + +### 语言风格 +- ❌ 避免:"首先、其次、最后" +- ❌ 避免:"众所周知" +- ✅ 使用:"我发现"、"我试过" +- ✅ 使用:"你也可以"、"很简单" + +--- + +## 🎯 文章亮点 + +### 独特卖点 +1. **真实数据** - 不是理论,是实际优化结果 +2. **通俗易懂** - 生活博主也能看懂 +3. **可复用** - 读者可以直接照着做 +4. **效果明显** - 40%的提升很震撼 + +### 差异化 +- 其他文章:讲技术原理 +- 你的文章:讲实际效果 + 简单方案 + +--- + +## 📅 写作计划 + +### 第1天:素材收集 +- [ ] 整理优化前后的数据 +- [ ] 截图关键页面 +- [ ] 准备代码示例 + +### 第2天:初稿写作 +- [ ] 按大纲写完整初稿 +- [ ] 插入截图和代码 +- [ ] 检查逻辑连贯性 + +### 第3天:润色发布 +- [ ] 精简语言,删除冗余 +- [ ] 优化标题和开头 +- [ ] 检查错别字 +- [ ] 发布并分享 + +--- + +## 💡 进阶建议 + +### 如果想更深入 +- 添加"常见问题"章节 +- 提供不同Hugo主题的适配方案 +- 分享自动化脚本 + +### 如果想更简洁 +- 只保留"问题→方案→效果"三部分 +- 删除技术细节,只留结论 +- 用对比图代替文字描述 + +--- + +**文档版本:** v1.0 +**创建日期:** 2026-06-03 +**适用场景:** 博客字体优化技术文章 diff --git a/static/nilaila-verify.txt b/static/nilaila-verify.txt new file mode 100644 index 00000000..496fe7ac --- /dev/null +++ b/static/nilaila-verify.txt @@ -0,0 +1 @@ +97dd49b8e6e941828e647b11bea73891 \ No newline at end of file diff --git a/write/.recycle/meta/202606041002.json b/write/.recycle/meta/202606041002.json new file mode 100644 index 00000000..8b137d1b --- /dev/null +++ b/write/.recycle/meta/202606041002.json @@ -0,0 +1,7 @@ +{ + "slug": "202606041002", + "title": "用Python给博客字体\"减肥\",加载速度快了一半", + "deletedAt": "2026-06-04T02:03:48.782Z", + "originalPath": "E:\\GitHub\\blog\\content\\posts\\2026\\2026-06-04-python-font-subsetting", + "expiresAt": "2026-07-04T02:03:48.782Z" +} \ No newline at end of file diff --git a/write/.recycle/posts/202606041002/index.md b/write/.recycle/posts/202606041002/index.md new file mode 100644 index 00000000..7934e869 --- /dev/null +++ b/write/.recycle/posts/202606041002/index.md @@ -0,0 +1,378 @@ +--- +title: 用Python给博客字体"减肥",加载速度快了一半 +date: 2026-06-04T10:00:00.000Z +draft: false +categories: + - 教程 + - 折腾 +tags: + - Hugo + - Python + - 字体优化 + - 性能优化 +author: 小赵同学 +layout: post +slug: '202606041002' +status: public +--- + +## 前言 + +折腾博客这么久了,性能优化一直是我比较在意的事情。前阵子给博客做了一波JS按需加载优化,效果还不错,首页JS从800KB直接砍到了350KB。 + +但是,我用Chrome DevTools的Network面板一看,好家伙,字体文件居然有1.2MB!比JS还大! + +说起来,之前也写过一篇用fontspider压缩字体的文章,但那个工具年久失修,对Hugo这种静态博客支持不太好。最近正好在学Python,发现了一个更好用的工具——**fonttools**,今天就来分享一下,怎么用Python给字体"减肥"。 + +## 为什么中文字体这么大? + +先给大家科普一下,为什么我们用的中文字体动不动就几MB。 + +中文字和英文字不一样。英文字母就26个大小写,加上数字和符号,撑死几百个字符。但中文呢?《通用规范汉字表》收录了8105个汉字,如果算上生僻字,得有好几万。 + +而字体文件里面,是把**所有字符的字形**都打包进去的。也就是说,不管你用没用到"龘"这个字,它都在你的字体文件里躺着,白白占空间。 + +但实际上,一个博客能用到多少字呢?我统计了一下我的博客,也就**2500个字符**左右。 + +**1.2MB的字体,实际只需要700多KB,剩下的都是浪费。** + +## 解决方案:Python + fonttools + +### 什么是fonttools? + +fonttools是一个Python库,专门用来处理字体文件。它能做很多事情,比如读取字体信息、转换格式、提取字符等等。 + +我们要用到的功能是**字体子集化**(Font Subsetting)——简单来说,就是只保留我们用到的字符,把其他的都扔掉。 + +### 安装环境 + +首先,你需要安装Python。这个就不多说了,去官网下载安装就行: + +https://www.python.org/downloads/ + +安装的时候记得勾选 **"Add Python to PATH"**,这样就能在命令行里直接用了。 + +装好之后,打开cmd,输入: + +```bash +python --version +``` + +能看到版本号就说明装好了。 + +然后安装fonttools和brotli(用于压缩): + +```bash +pip install fonttools brotli +``` + +如果提示权限不够,加上 `--break-system-packages`: + +```bash +pip install fonttools brotli --break-system-packages +``` + +## 编写优化脚本 + +接下来就是重头戏了,我写了一个Python脚本,可以自动扫描博客的所有内容,提取用到的字符,然后生成精简版字体。 + +在项目根目录创建一个文件:`scripts/subset-font-safe.py` + +```python +#!/usr/bin/env python3 +""" +字体子集化脚本 +从HTML和CSS文件中提取实际使用的字符,生成优化的子集字体 +""" + +import os +import re +from fontTools.ttLib import TTFont +from fontTools.subset import Subsetter, Options + +def extract_chars_from_files(directories): + """从文件中提取使用的字符""" + chars = set() + + for directory in directories: + if not os.path.exists(directory): + print(f"⚠️ 目录不存在,跳过: {directory}") + continue + + print(f"🔍 扫描目录: {directory}") + + for root, dirs, files in os.walk(directory): + for file in files: + if file.endswith(('.html', '.md', '.css')): + filepath = os.path.join(root, file) + try: + with open(filepath, 'r', encoding='utf-8') as f: + content = f.read() + # 提取中文字符 + chinese_chars = re.findall(r'[一-鿿]', content) + chars.update(chinese_chars) + # 提取英文和数字 + ascii_chars = re.findall(r'[a-zA-Z0-9]', content) + chars.update(ascii_chars) + # 提取常用标点 + en_punct = set('!@#$%^&*()_+-=[]{}|;:,.<>?/\\`~"\'-') + chars.update(en_punct) + except Exception as e: + print(f"⚠️ 读取失败 {filepath}: {e}") + + return chars + +def main(): + print("🔤 字体子集化工具") + print("=" * 50) + + # 配置路径 + font_dir = "themes/Ying/static/font" + input_font = os.path.join(font_dir, "zql-v2.woff2") + chars_file = os.path.join(font_dir, "used_chars.txt") + + # 检查输入文件 + if not os.path.exists(input_font): + print(f"❌ 字体文件不存在: {input_font}") + return + + # 读取现有的字符列表(如果有) + existing_chars = set() + if os.path.exists(chars_file): + with open(chars_file, 'r', encoding='utf-8') as f: + existing_chars = set(f.read()) + print(f"📖 读取现有字符: {len(existing_chars)} 个") + + # 扫描目录 + scan_dirs = ["content", "layouts"] + if os.path.exists("public"): + scan_dirs.append("public") + + # 提取字符 + new_chars = extract_chars_from_files(scan_dirs) + print(f"📝 从文件提取了 {len(new_chars)} 个字符") + + # 合并字符(保留手动添加的字符) + all_chars = existing_chars | new_chars + print(f"📊 合并后: {len(all_chars)} 个字符") + + # 保存字符列表 + with open(chars_file, 'w', encoding='utf-8') as f: + f.write(''.join(sorted(all_chars))) + + # 生成woff2子集 + output_woff2 = os.path.join(font_dir, "zql-v2-subset.woff2") + print(f"\n🎯 生成 woff2 子集字体...") + + font = TTFont(input_font) + options = Options() + options.flavor = 'woff2' + + subsetter = Subsetter(options=options) + subsetter.populate(text=''.join(all_chars)) + subsetter.subset(font) + font.save(output_woff2) + + # 计算优化效果 + original_size = os.path.getsize(input_font) + subset_size = os.path.getsize(output_woff2) + reduction = original_size - subset_size + percentage = (reduction / original_size) * 100 + + print(f"\n✅ 优化完成!") + print(f"📊 原始大小: {original_size / 1024:.1f} KB") + print(f"📊 子集大小: {subset_size / 1024:.1f} KB") + print(f"📊 减少: {reduction / 1024:.1f} KB ({percentage:.1f}%)") + +if __name__ == "__main__": + main() +``` + +### 脚本做了什么? + +这个脚本的逻辑很简单,分三步: + +1. **扫描**:遍历 `content`、`layouts`、`public` 目录,找出所有用到的字符 +2. **提取**:把中文、英文、数字、标点符号都提取出来 +3. **生成**:用fonttools生成只包含这些字符的字体 + +这里有个细节:脚本会读取 `used_chars.txt` 里手动添加的字符。这样如果你有一些特殊字符(比如我博客里的古风官职表),可以手动加进去,不会被覆盖。 + +## 运行效果 + +首先,确保你已经构建过Hugo: + +```bash +hugo --destination=public +``` + +然后运行脚本: + +```bash +python scripts/subset-font-safe.py +``` + +我这边的运行结果: + +``` +🔤 字体子集化工具 +================================================== +📖 读取现有字符: 2489 个 +🔍 扫描目录: content +🔍 扫描目录: layouts +🔍 扫描目录: public +📝 从文件提取了 2492 个字符 +📊 合并后: 2500 个字符 + +🎯 生成 woff2 子集字体... + +✅ 优化完成! +📊 原始大小: 1226.6 KB +📊 子集大小: 740.7 KB +📊 减少: 485.9 KB (39.6%) +``` + +**1.2MB的字体,优化后只剩740KB,减少了40%!** + +## 更新CSS + +字体文件生成了,还需要告诉浏览器用新的字体。打开 `themes/Ying/assets/css/main.css`,找到字体声明: + +```css +@font-face { + font-family: 'zql'; + src: url('../font/zql-v2.woff2') format('woff2'), + url('../font/zql-v2.woff') format('woff'); + font-display: swap; + unicode-range: U+0000-007F, U+4E00-9FFF, U+2000-206F, U+3000-303F; +} +``` + +改成: + +```css +@font-face { + font-family: 'zql'; + src: url('../font/zql-v2-subset.woff2') format('woff2'), + url('../font/zql-v2-subset.woff') format('woff'); + font-display: swap; +} +``` + +注意两个变化: +- 文件名加了 `-subset` 后缀 +- 删掉了 `unicode-range`(因为子集字体已经只包含需要的字符了) + +## 自动化:GitHub Actions + +每次写完文章都要手动跑一遍脚本,太麻烦了。不如让GitHub Actions帮你自动做。 + +在 `.github/workflows/` 下创建一个 `subset-fonts.yml`: + +```yaml +name: Font Subset Optimization + +on: + push: + branches: + - main + paths: + - 'content/**' + - 'layouts/**' + schedule: + - cron: '0 2 * * 1' # 每周一凌晨2点 + +jobs: + subset-fonts: + name: Subset Fonts + runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + contents: write + + if: github.repository == '你的用户名/你的仓库名' + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + pip install fonttools brotli + + - name: Build Hugo site + uses: peaceiris/actions-hugo@v2 + with: + hugo-version: '0.128.2' + extended: true + + - name: Build + run: hugo --destination=public --minify + + - name: Subset fonts + run: python scripts/subset-font-safe.py + + - name: Commit and push + run: | + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git add themes/Ying/static/font/zql-v2-subset.* + git add themes/Ying/static/font/used_chars.txt + if ! git diff --staged --quiet; then + git commit -m "chore: update font subset [skip ci]" + git push origin main + fi +``` + +注意那个 `[skip ci]`,这是为了避免触发循环——字体更新了又触发一次构建,构建完了又更新字体…… + +## 最终效果 + +优化前后的数据对比: + +| 指标 | 优化前 | 优化后 | 提升 | +|------|--------|--------|------| +| 字体大小 | 1.2 MB | 740 KB | -40% | +| 首页加载 | ~3秒 | ~1.8秒 | -40% | +| PageSpeed得分 | 60 | 85 | +42% | + +说实话,39.6%的减少没有达到我预期的80%+。原因是我博客里的内容比较杂,各种字符都有用到,古风官职表、数学符号、特殊标点……能优化到这个程度已经很不错了。 + +如果你的博客内容比较单一(比如纯技术博客),优化效果会更好,可能能到60%-70%。 + +## 常见问题 + +### Q:优化后有些字显示不出来了? + +这说明有些字符没有被提取到。解决方法: + +1. 检查 `used_chars.txt`,看看缺失的字符在不在里面 +2. 如果不在,手动添加进去,然后重新运行脚本 +3. 如果是API返回的动态内容,需要把API返回的字符也加入字符集 + +### Q:脚本报错 `function "try" not defined`? + +这是Hugo版本问题。这个脚本和Hugo版本无关,直接用Python运行就行。 + +### Q:能不能把优化效果做得更好? + +可以试试: +- 扫描更多目录(比如API返回的数据) +- 使用更小的字符集(比如只包含GB2312常用字6763个) +- 用在线工具手动选择字符 + +## 写在最后 + +博客优化就像减肥,找对方法,效果立竿见影。 + +字体优化这个事情,说大不大,说小不小。单独看可能只减少了400KB,但配合之前的JS优化,整体加载时间直接砍了一半。 + +而且最爽的是,这些优化都是一劳永逸的。写一次脚本,配好GitHub Actions,以后写文章完全不用管,自动就给你优化好了。 + +如果你也被博客加载速度困扰,不妨试试这个方案。有问题欢迎评论区交流~ +