﻿---
title: "去哪找好用的 SVG：资源实测，以及怎么给 AI 画图当参照"
description: "本站的配图是让 AI 写 SVG 画的，画得好不好，取决于给它看什么参照。为了找好的参照，顺着这些问题往下追：SVG 资源分哪几类，“免费”背后有哪几种许可、哪些不让拿给 AI，各家插画站的风格和文件质量差在哪，23 套图标库为什么有的能跟着文字变色、有的不能，聚合站里的许可为什么要逐个看，SVG 放进页面之前要处理什么；最后是让 AI 画什么就搜什么、把搜到的 SVG 当 baseline 而不是素材，prompt 怎么写，画完怎么对照。"
pubDate: 2026-10-28
updatedDate: 2026-10-28
tags: ["SVG", "设计资源", "图标", "开源许可", "前端"]
hero: "./hero.svg"
clc: "TP39"
refs:
  - id: undraw
    title: unDraw License
    url: https://undraw.co/license
    site: unDraw
    note: "商用免费、不用署名；不能做竞品或打包再分发，不能用于 AI 训练，未经同意不能自动抓取下载。"
  - id: openpeeps
    title: Open Peeps
    url: https://www.openpeeps.com
    author: Pablo Stanley
    note: CC0
  - id: humaaans
    title: Humaaans
    url: https://www.humaaans.com
    author: Pablo Stanley
    note: CC0
  - id: opendoodles
    title: About Open Doodles
    url: https://opendoodles.com/about
    author: Pablo Stanley
    note: CC0
  - id: storyset
    title: Storyset Terms of Use
    url: https://storyset.com/terms
    site: Storyset（Freepik）
    note: "免费使用须注明出处；不署名需要购买 Flaticon Premium。"
  - id: drawkit
    title: DrawKit License
    url: https://www.drawkit.com/license
    site: DrawKit
    note: "商用不用署名；不能再分发、不能放进模板、不能印成周边、不能用于 AI 训练。"
  - id: manypixels
    title: ManyPixels Free Illustrations
    url: https://www.manypixels.co/gallery
    site: ManyPixels
    note: "页面底部许可：商用不用署名，不能打包再分发或做竞品。"
  - id: iradesign
    title: IRA Design
    url: https://iradesign.io
    note: MIT
  - id: blush
    title: Blush License
    url: https://blush.design/license
    site: Blush
  - id: icons8
    title: "Icons8 社区：Free license attribution requirements"
    url: https://community.icons8.com/t/free-license-attribution-requirements/1708
    site: Icons8 Community
    note: "Icons8 许可页对本文的抓取返回 403，免费版要署名加链接、SVG 收费这两点来自官方论坛和定价页。"
  - id: openclipart
    title: Openclipart Share
    url: https://openclipart.org/share
    site: Openclipart
    note: "18 万余幅矢量图，全部放入公有领域。"
  - id: commons
    title: "File:Tux.svg"
    url: https://commons.wikimedia.org/wiki/File:Tux.svg
    site: Wikimedia Commons
    note: "Tux 由 Larry Ewing 用 GIMP 绘制，使用时要注明作者。"
  - id: heropatterns
    title: Hero Patterns
    url: https://heropatterns.com
    author: Steve Schoger
    note: "页面底部标注 CC BY 4.0；图案数据在 `/js/app.js`。"
  - id: fffuel
    title: License for images generated using fffuel tools
    url: https://fffuel.co/license/
    site: fffuel
  - id: haikei
    title: Haikei
    url: https://haikei.app
    note: "首页写着免费、不用注册；没有找到单独的许可页。"
  - id: svgbackgrounds
    title: SVGBackgrounds.com License
    url: https://www.svgbackgrounds.com/license/
    site: SVG Backgrounds
  - id: gameicons
    title: game-icons.net About
    url: https://game-icons.net/about.html
    note: CC BY 3.0
  - id: remixlicense
    title: Remix Icon License v1.0
    url: https://github.com/Remix-Design/remixicon/blob/master/License
    site: GitHub
    note: "2026 年 1 月生效。npm 包 remixicon 4.9.1 的 package.json 仍写 Apache-2.0。"
  - id: fontawesome
    title: Font Awesome Free License
    url: https://fontawesome.com/license/free
    site: Font Awesome
    note: "图标 CC BY 4.0，字体 OFL 1.1，代码 MIT；每个 SVG 文件里自带一行许可注释。"
  - id: simpleicons
    title: Simple Icons
    url: https://github.com/simple-icons/simple-icons
    site: GitHub
    note: "图标文件 CC0，但品牌标志本身受各自商标约束。"
  - id: lucide
    title: Lucide
    url: https://lucide.dev
    note: "ISC；本文实测 lucide-static 1.62.0。"
  - id: tabler
    title: Tabler Icons
    url: https://tabler.io/icons
    note: "MIT；本文实测 @tabler/icons 3.50.0。"
  - id: phosphor
    title: Phosphor Icons
    url: https://phosphoricons.com
    note: "MIT；thin、light、regular、bold、fill、duotone 六种字重。"
  - id: material
    title: Material Symbols
    url: https://fonts.google.com/icons
    site: Google Fonts
    note: Apache-2.0
  - id: iconify
    title: Iconify API：/collections
    url: https://api.iconify.design/collections
    site: Iconify
    note: "2026-10-28 返回 244 套、417,719 个图标，每套带 license 字段。"
  - id: svgrepo
    title: SVG Repo Licensing
    url: https://www.svgrepo.com/page/licensing/
    site: SVG Repo
    note: "本文的 curl 和抓取都收到 429；许可说明来自搜索摘要：默认不要求署名，但条款按作者不同。"
  - id: themehope
    title: "vuepress-theme-hope：图标支持"
    url: https://theme-hope.vuejs.press/zh/guide/interface/icon.html
    site: VuePress Theme Hope
    note: "提醒商用项目慎用 iconfont：图标由用户上传，商用须作者授权，上传者也可能上传了版权在第三方的图标。"
  - id: svgo
    title: "SVGO：prefixIds"
    url: https://svgo.dev/docs/plugins/prefixIds/
    site: SVGO
  - id: currentcolor
    title: "currentcolor keyword"
    url: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#currentcolor_keyword
    site: MDN
  - id: iconifysearch
    title: "Iconify API：/search"
    url: https://iconify.design/docs/api/search.html
    site: Iconify
    note: "按关键词搜图标，可用 `prefix` 限定在一套图标里；单个 SVG 从 `/<前缀>/<名字>.svg` 取。"
  - id: ccby
    title: Creative Commons Attribution 4.0 International
    url: https://creativecommons.org/licenses/by/4.0/
    site: Creative Commons
---

本站每篇文章的头图和配图，都是让 AI 直接写 SVG 代码画出来的。画多了会发现，AI 画得好不好，很大程度上取决于它“照着什么画”。只说一句“画一个简洁的图标”，线宽、网格、圆角全凭它自己的印象，每次都不一样；给它看几张好的 SVG，画出来就稳得多。这里的“看”不是让 AI 把别人的 SVG 扒下来直接用，而是给它一条 baseline：风格向谁看齐，质量要到什么程度，画完以后拿什么来对照。

于是就要去找好的 SVG。搜 “free SVG illustrations”，能搜出一长串站点，每个都写着 free。真下载了几张，事情没那么顺。一张 unDraw 的插画放进页面，主色是一种很显眼的紫色 `#6c63ff`，和本站的暖色完全不搭；一张 Open Peeps 的手绘人物在浅色模式下很好看，切到深色模式，黑色线条就和背景融成一片；从图标库里拿来的房子图标，用 `<img>` 引进来以后，怎么设 `color` 都还是黑的。再往页脚看，“free” 后面还跟着小字：有的要求署名，有的禁止拿去训练 AI，有的只免费给低清 PNG。

那么，哪里能找到质量好一点、适合当参照的 SVG？各家写的“免费”是同一个意思，允许拿给 AI 看吗？下载下来的文件，放进网页之前要做什么？真要让 AI 照着画，又该怎么跟它说？本文就从这几个疑问出发，把插画、图标、图案三类资源逐个下载下来试一遍，最后再让 AI 照着画一次。

## 一、SVG 资源的几种来源

搜出来的站混在一起，其实是几种不同的东西。按“一个文件里装的是什么”，可以分成四类：

- **插画**：一个场景或一个人物，几十个到几百个形状，用来做头图、空状态、落地页。代表是 unDraw、Open Peeps、Storyset。
- **图标**：一个符号，通常画在 24×24 这样的小网格上，几百字节，成套出现，一套几百到几千个。代表是 Lucide、Tabler、Material Symbols。
- **图案与背景**：可以平铺的纹样，或者由生成器现场算出来的波浪、斑点。代表是 Hero Patterns、Haikei。
- **聚合站和开放图库**：自己不画，把别人的作品汇到一起供搜索。代表是 Iconify、SVG Repo、iconfont.cn、Openclipart、Wikimedia Commons。

四类东西的“好”不是一个标准。插画看风格能不能统一、能不能改成自己的配色；图标看成套程度和能不能跟着文字变色；图案看能不能无缝平铺、体积多大；聚合站看能不能按许可筛选。拿来给 AI 当参照，还要多看一条：**规格能不能量化**。一套图标的网格、线宽、圆角都是固定的数字，可以原样写给 AI，也可以拿来检查它画出来的东西；一张孤零零的插画，只能让 AI 去“意会”。但有一件事四类都绕不开：每个站都写着 free，**这个 free 到底允许我们做什么？**

## 二、“免费”的几种含义

### 现象

把各站的许可页一个个点开（2026 年 10 月 28 日访问），“free” 至少有六种意思。Open Peeps 说的是 “CC0，你可以复制、修改、分发，甚至商用，不用问任何人”[^openpeeps]；Storyset 说的是“免费使用，前提是注明出处，不想署名就买 Flaticon Premium”[^storyset]；unDraw 说的是“商用免费、不用署名”，后面紧跟着三条禁止：不能做竞品或打包再分发，不能用于训练 AI，不能未经同意自动抓取下载[^undraw]。

### 分析

这些说法可以归成下面几类。前四类是通用许可，条款在任何地方都一样；后两类是站点自己写的，要逐条读。

<figure class="dd dd-figure dt-figure">
<div class="dt-panel">
<div class="dt-title" id="svr-lic-title">“免费”的六种含义</div>
<div class="dt-scroll">
<table class="dt" aria-labelledby="svr-lic-title">
<colgroup><col style="width:20%"><col style="width:16%"><col style="width:16%"><col></colgroup>
<thead>
<tr><th scope="col">类型</th><th scope="col">商用</th><th scope="col">署名</th><th scope="col">要留意的地方 · 例子</th></tr>
</thead>
<tbody>
<tr><th scope="row">公有领域 CC0</th><td class="good">可以</td><td class="good">不用</td><td>没有附加条件。Open Peeps、Humaaans、Open Doodles、Openclipart、Simple Icons（品牌商标另算）</td></tr>
<tr><th scope="row">宽松开源 MIT / ISC / Apache-2.0</th><td class="good">可以</td><td class="good">页面上不用</td><td>分发副本时要带上版权声明，通常在源码或致谢页留一行。Lucide、Tabler、Heroicons、Phosphor、Material Symbols、IRA Design</td></tr>
<tr><th scope="row">署名 CC BY</th><td class="good">可以</td><td class="warn">要</td><td>写明作者、来源和许可。Hero Patterns、Font Awesome Free、game-icons.net</td></tr>
<tr><th scope="row">相同方式共享 CC BY-SA、GPL</th><td class="good">可以</td><td class="warn">要</td><td>改过的作品要用同样的许可发布。OpenMoji、Typicons、WordPress Dashicons</td></tr>
<tr><th scope="row">站点自定义许可</th><td class="good">可以</td><td>多数不用</td><td class="warn">逐条读禁止项：不能打包再分发、不能做竞品、不能 AI 训练、不能当商标。unDraw、DrawKit、ManyPixels、fffuel、Remix Icon（2026 起）</td></tr>
<tr><th scope="row">免费增值</th><td>免费版可以</td><td class="bad">免费版要</td><td>付费才去署名或给 SVG。Storyset、Icons8、SVG Backgrounds</td></tr>
</tbody>
</table>
</div>
<p class="dt-note">还有一类要绕开：CC BY-NC（非商业）。个人博客挂了广告，算不算商业用途，许可本身说不清。</p>
</div>
<figcaption>图 1 · 同样写着 free，六类许可对商用和署名的要求各不相同</figcaption>
</figure>

站点自定义许可最容易被忽略，因为它的第一句往往和 CC0 一样宽松。DrawKit 允许商用、不用署名，但不允许把插画放进要下载的博客模板里，也不允许印到 T 恤和杯子上[^drawkit]。

这类禁止项里，和本文目的关系最大的是 AI。unDraw 的许可专门列了一串：不能拿来做生成式模型的训练数据，不能放进机器学习数据集，不能“用来训练、验证或测试 AI 系统”，也不能为开发 AI 模型做任何自动化处理；还不能未经同意自动抓取下载[^undraw]。DrawKit 也写明不能用于训练、微调或改进任何 AI 模型[^drawkit]。把一张插画贴进 prompt 当参照算不算这些条款里的“使用”，条文没有说清。既然有 CC0、MIT 的同类可选，**给 AI 当参照的素材就从许可宽松的库里挑，避开写了 AI 禁令的站**。

### 许可会变

还有一个容易踩的坑：许可不是一成不变的。Remix Icon 从 2026 年 1 月起改用自己写的 Remix Icon License v1.0，新加了三条禁止：不能单独售卖图标、不能拿它做竞品图标库、不能把图标当 logo 或商标用[^remixlicense]。我们用 npm 装下最新的 remixicon 4.9.1，`package.json` 里写的却还是 `"license": "Apache-2.0"`，只有包里的 `License` 文件是新条款。

按 `package.json` 自动统计许可的工具，会把它当成 Apache-2.0。**判断许可要看许可文件本身，不能只看包的元数据。**

### 聚合站里的许可分布

聚合站把这件事放大了。Iconify 的接口会返回每套图标的许可[^iconify]，我们把 244 套、417,719 个图标按许可加起来：

<figure class="dd dd-figure">
<div class="dd-scroll">
<svg class="dd-svg" viewBox="0 0 800 420" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="svr-iconify-title svr-iconify-desc">
<title id="svr-iconify-title">Iconify 收录图标的许可分布</title>
<desc id="svr-iconify-desc">244 套图标中，MIT 和 Apache-2.0 占大头；CC BY、CC BY-SA、CC BY-NC 和 GPL 四类合计 95,439 个图标，约占 23%，使用时要署名或遵守附加条款。</desc>
<rect class="dd-frame" width="800" height="420" rx="10"/>
<rect class="dd-zone" x="16" y="16" width="768" height="388" rx="8"/>
<text class="t-zone" x="40" y="44">Iconify 收录的 244 套图标，按许可加总（图标个数）</text>
<text class="t-name" x="40" y="83">MIT · 113 套</text>
<rect class="dd-track" x="220" y="70" width="480" height="16" rx="3"/>
<text class="t-val" x="710" y="83">213,714</text>
<text class="t-name" x="40" y="113">Apache-2.0 · 31 套</text>
<rect class="dd-track" x="220" y="100" width="189" height="16" rx="3"/>
<text class="t-val" x="419" y="113">84,280</text>
<text class="t-name t-acc" x="40" y="143">CC BY · 53 套</text>
<rect class="dd-fill-acc" x="220" y="130" width="155" height="16" rx="3"/>
<text class="t-val" x="385" y="143">68,918</text>
<text class="t-name t-acc" x="40" y="173">CC BY-SA · 9 套</text>
<rect class="dd-fill-acc" x="220" y="160" width="51" height="16" rx="3"/>
<text class="t-val" x="281" y="173">22,739</text>
<text class="t-name" x="40" y="203">CC0 · 10 套</text>
<rect class="dd-track" x="220" y="190" width="25" height="16" rx="3"/>
<text class="t-val" x="255" y="203">11,193</text>
<text class="t-name" x="40" y="233">OFL-1.1 · 13 套</text>
<rect class="dd-track" x="220" y="220" width="14" height="16" rx="3"/>
<text class="t-val" x="244" y="233">6,240</text>
<text class="t-name" x="40" y="263">ISC · 4 套</text>
<rect class="dd-track" x="220" y="250" width="13" height="16" rx="3"/>
<text class="t-val" x="243" y="263">5,925</text>
<text class="t-name t-acc" x="40" y="293">CC BY-NC · 2 套</text>
<rect class="dd-fill-acc" x="220" y="280" width="5" height="16" rx="2"/>
<text class="t-val" x="235" y="293">2,245</text>
<text class="t-name t-acc" x="40" y="323">GPL · 6 套</text>
<rect class="dd-fill-acc" x="220" y="310" width="4" height="16" rx="2"/>
<text class="t-val" x="234" y="323">1,537</text>
<text class="t-name" x="40" y="353">Unlicense、MPL、BSD · 3 套</text>
<rect class="dd-track" x="220" y="340" width="3" height="16" rx="1"/>
<text class="t-val" x="233" y="353">928</text>
<text class="t-say" x="40" y="388">橙色四类合计 95,439 个，约占 23%：要署名，或改了以后要用同样的许可发布，或不能商用。</text>
</svg>
</div>
<figcaption>图 2 · 同一个聚合站里，大约每四个图标就有一个带附加条件</figcaption>
</figure>

将近四分之三的图标是 MIT、Apache 这类宽松许可，但剩下四分之一要署名或带附加条款，其中 Custom Brand Icons 和 PrestaShop Icons 两套还是非商业许可。在聚合站里搜图标，搜到的是图标，许可却要回到它所属的那一套去看。

许可弄清楚了，接下来按类型看资源本身。先看插画，因为插画最显眼，问题也最多。

## 三、插画资源

### 各家的风格和许可

免费 SVG 插画站数下来有十来家，风格差别很大：

- **unDraw**：扁平人物 + 一个主色，主题偏科技和办公。站上可以先选主色再下载[^undraw]。
- **Open Peeps / Humaaans**：同一位作者 Pablo Stanley 的两套“积木”。Open Peeps 是黑白手绘线稿，Humaaans 是彩色扁平人物，头、身体、腿可以自由拼装，都是 CC0[^openpeeps][^humaaans]。
- **Open Doodles**：同一位作者的涂鸦风，只有一个强调色加黑线，CC0[^opendoodles]。
- **Storyset**：Freepik 出品的场景插画，可以在线换主色、加简单动画；免费版要署名[^storyset]。
- **DrawKit、ManyPixels**：商业公司放出的免费插画，许可都是“商用不用署名、不能再分发”的自定义条款[^drawkit][^manypixels]。
- **IRA Design**：渐变色人物和物件组件，MIT[^iradesign]。
- **Blush**：汇集多位插画师的风格，可以在线拼装；许可页写明免费使用不用署名[^blush]。
- **Icons8 Ouch**：风格最多，但免费版只给低清 PNG，还要署名加链接，SVG 要付费[^icons8]。
- **Openclipart、Wikimedia Commons**：开放图库，数量最大，风格完全不统一[^openclipart][^commons]。

只看许可和风格还不够。我们从其中几家各下载了一两张，用同一个脚本统计文件里有什么：

<figure class="dd dd-figure dt-figure">
<div class="dt-panel">
<div class="dt-title" id="svr-illus-title">插画样本实测（原始文件，svgo multipass 压缩后）</div>
<div class="dt-scroll">
<table class="dt dt-sticky" aria-labelledby="svr-illus-title">
<colgroup><col style="width:26%"><col><col><col><col></colgroup>
<thead>
<tr><th scope="col">样本</th><th scope="col">体积</th><th scope="col">颜色数</th><th scope="col">id 数</th><th scope="col">svgo 后</th></tr>
</thead>
<tbody>
<tr><th scope="row">unDraw · agentic-network</th><td class="num mono">23.1 KB</td><td class="num mono acc">8</td><td class="num mono good">0</td><td class="num mono">20.3 KB</td></tr>
<tr><th scope="row">unDraw · business-chart</th><td class="num mono">8.2 KB</td><td class="num mono acc">4</td><td class="num mono warn">1（a）</td><td class="num mono">7.0 KB</td></tr>
<tr><th scope="row">Open Peeps · peep-1</th><td class="num mono">39.0 KB</td><td class="num mono acc">2</td><td class="num mono">15</td><td class="num mono">16.7 KB</td></tr>
<tr><th scope="row">Humaaans · wide-shot</th><td class="num mono">79.6 KB</td><td class="num mono">26</td><td class="num mono">207</td><td class="num mono">31.0 KB</td></tr>
<tr><th scope="row">Open Doodles · coffee</th><td class="num mono">42.7 KB</td><td class="num mono acc">2</td><td class="num mono">59</td><td class="num mono">20.6 KB</td></tr>
<tr><th scope="row">Storyset · team-work</th><td class="num mono">45.6 KB</td><td class="num mono acc">6</td><td class="num mono">20</td><td class="num mono">31.2 KB</td></tr>
<tr><th scope="row">Openclipart · iso-house</th><td class="num mono bad">359.5 KB</td><td class="num mono">40</td><td class="num mono bad">981</td><td class="num mono">181.7 KB</td></tr>
<tr><th scope="row">Wikimedia · Tux</th><td class="num mono">48.8 KB</td><td class="num mono">47</td><td class="num mono">163</td><td class="num mono">35.1 KB</td></tr>
</tbody>
</table>
</div>
<p class="dt-note">颜色数是文件里出现的不同十六进制色值个数。Humaaans、Open Peeps、Open Doodles 的 id 都是设计软件里的图层名，Openclipart 和 Tux 的 id 大多被渐变、滤镜引用。</p>
</div>
<figcaption>图 3 · 同样是免费插画，文件里的颜色数、id 数和冗余程度差好几倍</figcaption>
</figure>

### 改成自己的配色

开头那张紫色的 unDraw 插画，问题出在配色上。表里的“颜色数”恰好说明了改色的难度：unDraw 那张 agentic-network 一共 8 种颜色，其中主色 `#6c63ff` 出现了 30 次，其余是灰和深蓝。**把这一个色值全局替换成站点的强调色，整张图就换了主题**，这也是 unDraw 能在网站上先选主色再下载的原因。Open Doodles 是 `#ff5678` 加黑线，Storyset 是一个主色加几种灰，改法一样。

Humaaans 就难得多：一张图 26 种颜色，肤色、衣服、阴影各是各的，要改只能进设计软件逐个调。Openclipart 和 Wikimedia 上的图更是各画各的，40 多种颜色、几十个渐变很常见。

颜色数也决定了一张插画适不适合给 AI 当参照。Open Doodles 是“黑线加一个强调色”，Open Peeps 只有黑白两色，风格一句话就能写清，AI 也容易照着做；Humaaans 的 26 种颜色和 207 个图层 id，AI 读进去只是一堆噪声。

### 深色模式

颜色能换，还有一个问题没解决：深色模式。Open Peeps 的线条是写死的 `#000000`，本站深色模式的页面底色是 `#111`，两者的对比度只有 1.1:1，线条几乎看不见。unDraw 的深色部分 `#3f3d56` 在同样的底色上也只有 1.8:1。

写死颜色的插画在深色模式下只有三种处理办法：给插画垫一块浅色底，让它像一张贴纸；把关键颜色改成 CSS 类，深色模式下另给一组颜色（本站自己的配图就是这么做的）；或者只在浅色模式下显示。第一种最省事，第二种效果最好，但要先把文件里的颜色整理成少数几个，前面那张表里颜色越少的，越容易做。

插画在一个页面里通常只放一两张，而图标一放就是几十个，遇到的问题又不一样了。

## 四、图标库

### 同类图标库列全

开源 SVG 图标库数量多，但主流的就二十来套。我们用 npm 和 Iconify 的数据包装下了其中 23 套，每套取“房子”这个图标放在一起看：

<figure class="dd dd-figure">
<div class="dd-scroll">
<svg class="dd-svg" viewBox="0 0 800 400" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="svr-house-title svr-house-desc">
<title id="svr-house-title">12 套图标库里的房子图标</title>
<desc id="svr-house-desc">上排 6 套是描边图标：Lucide、Heroicons、Tabler、Feather、Iconoir、IconPark；下排 6 套是填充图标：Phosphor、Material Symbols、Remix、Bootstrap、MDI、Carbon。每个图标下面标出它的设计网格。</desc>
<style>
.dd-svg .svr-ic{color:var(--dd-ink)}
.dd-svg .svr-nofill{fill:var(--dd-ink)}
</style>
<rect class="dd-frame" width="800" height="400" rx="10"/>
<rect class="dd-zone" x="16" y="16" width="768" height="176" rx="8"/>
<rect class="dd-zone" x="16" y="208" width="768" height="176" rx="8"/>
<text class="t-zone" x="40" y="44">描边（stroke）：画的是线，线宽写在属性里</text>
<text class="t-zone" x="40" y="236">填充（fill）：画的是轮廓，线宽已经“画死”在形状里</text>
<svg class="svr-ic" x="68" y="72" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8" /><path d="M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" /></svg>
<text class="t-name" x="92" y="146" text-anchor="middle">Lucide</text>
<text class="t-note" x="92" y="166" text-anchor="middle">24×24</text>
<svg class="svr-ic" x="192" y="72" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="m2.25 12 8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25"/></svg>
<text class="t-name" x="216" y="146" text-anchor="middle">Heroicons</text>
<text class="t-note" x="216" y="166" text-anchor="middle">24×24</text>
<svg class="svr-ic" x="316" y="72" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M5 12l-2 0l9 -9l9 9l-2 0" /><path d="M5 12v7a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-7" /><path d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v6" /></svg>
<text class="t-name" x="340" y="146" text-anchor="middle">Tabler</text>
<text class="t-note" x="340" y="166" text-anchor="middle">24×24</text>
<svg class="svr-ic" x="440" y="72" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg>
<text class="t-name" x="464" y="146" text-anchor="middle">Feather</text>
<text class="t-note" x="464" y="166" text-anchor="middle">24×24</text>
<svg class="svr-ic" x="564" y="72" width="48" height="48" viewBox="0 0 24 24" stroke-width="1.5" fill="none"><path d="M2 8L11.7317 3.13416C11.9006 3.04971 12.0994 3.0497 12.2683 3.13416L22 8" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/><path d="M20 11V19C20 20.1046 19.1046 21 18 21H6C4.89543 21 4 20.1046 4 19V11" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/></svg>
<text class="t-name" x="588" y="146" text-anchor="middle">Iconoir</text>
<text class="t-note" x="588" y="166" text-anchor="middle">24×24</text>
<svg class="svr-ic" x="688" y="72" width="48" height="48" viewBox="0 0 48 48"><g fill="none" stroke="currentColor" stroke-width="4"><path stroke-linecap="round" stroke-linejoin="round" d="M9 18v24h30V18L24 6z"/><path stroke-linejoin="round" d="M19 29v13h10V29z"/><path stroke-linecap="round" d="M9 42h30"/></g></svg>
<text class="t-name" x="712" y="146" text-anchor="middle">IconPark</text>
<text class="t-note" x="712" y="166" text-anchor="middle">48×48</text>
<svg class="svr-ic" x="68" y="264" width="48" height="48" viewBox="0 0 256 256" fill="currentColor"><path d="M219.31,108.68l-80-80a16,16,0,0,0-22.62,0l-80,80A15.87,15.87,0,0,0,32,120v96a8,8,0,0,0,8,8h64a8,8,0,0,0,8-8V160h32v56a8,8,0,0,0,8,8h64a8,8,0,0,0,8-8V120A15.87,15.87,0,0,0,219.31,108.68ZM208,208H160V152a8,8,0,0,0-8-8H104a8,8,0,0,0-8,8v56H48V120l80-80,80,80Z"/></svg>
<text class="t-name" x="92" y="338" text-anchor="middle">Phosphor</text>
<text class="t-note" x="92" y="358" text-anchor="middle">256×256</text>
<svg class="svr-ic svr-nofill" x="192" y="264" width="48" height="48" viewBox="0 -960 960 960"><path d="M220-180h150v-250h220v250h150v-390L480-765 220-570v390Zm-60 60v-480l320-240 320 240v480H530v-250H430v250H160Zm320-353Z"/></svg>
<text class="t-name" x="216" y="338" text-anchor="middle">Material</text>
<text class="t-note" x="216" y="358" text-anchor="middle">960×960</text>
<svg class="svr-ic" x="316" y="264" width="48" height="48" viewBox="0 0 24 24" fill="currentColor"><path d="M21 20C21 20.5523 20.5523 21 20 21H4C3.44772 21 3 20.5523 3 20V9.48907C3 9.18048 3.14247 8.88917 3.38606 8.69972L11.3861 2.47749C11.7472 2.19663 12.2528 2.19663 12.6139 2.47749L20.6139 8.69972C20.8575 8.88917 21 9.18048 21 9.48907V20ZM19 19V9.97815L12 4.53371L5 9.97815V19H19Z"/></svg>
<text class="t-name" x="340" y="338" text-anchor="middle">Remix</text>
<text class="t-note" x="340" y="358" text-anchor="middle">24×24</text>
<svg class="svr-ic" x="440" y="264" width="48" height="48" viewBox="0 0 16 16" fill="currentColor"><path d="M8.707 1.5a1 1 0 0 0-1.414 0L.646 8.146a.5.5 0 0 0 .708.708L2 8.207V13.5A1.5 1.5 0 0 0 3.5 15h9a1.5 1.5 0 0 0 1.5-1.5V8.207l.646.647a.5.5 0 0 0 .708-.708L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293zM13 7.207V13.5a.5.5 0 0 1-.5.5h-9a.5.5 0 0 1-.5-.5V7.207l5-5z"/></svg>
<text class="t-name" x="464" y="338" text-anchor="middle">Bootstrap</text>
<text class="t-note" x="464" y="358" text-anchor="middle">16×16</text>
<svg class="svr-ic svr-nofill" x="564" y="264" width="48" height="48" viewBox="0 0 24 24"><path d="M12 5.69L17 10.19V18H15V12H9V18H7V10.19L12 5.69M12 3L2 12H5V20H11V14H13V20H19V12H22" /></svg>
<text class="t-name" x="588" y="338" text-anchor="middle">MDI</text>
<text class="t-note" x="588" y="358" text-anchor="middle">24×24</text>
<svg class="svr-ic svr-nofill" x="688" y="264" width="48" height="48" viewBox="0 0 32 32"><path d="M16.6123,2.2138a1.01,1.01,0,0,0-1.2427,0L1,13.4194l1.2427,1.5717L4,13.6209V26a2.0041,2.0041,0,0,0,2,2H26a2.0037,2.0037,0,0,0,2-2V13.63L29.7573,15,31,13.4282ZM18,26H14V18h4Zm2,0V18a2.0023,2.0023,0,0,0-2-2H14a2.002,2.002,0,0,0-2,2v8H6V12.0615l10-7.79,10,7.8005V26Z"/></svg>
<text class="t-name" x="712" y="338" text-anchor="middle">Carbon</text>
<text class="t-note" x="712" y="358" text-anchor="middle">32×32</text>
</svg>
</div>
<figcaption>图 4 · 同一个“房子”，网格从 16 到 960、线宽从 1.5 到 2，混用两套图标一眼就能看出来</figcaption>
</figure>

图里的文件都是各库发布的原样，只去掉了尺寸和注释。12 套用了六种网格（16、24、32、48、256、960），同是 24 网格，Heroicons 和 Iconoir 的线宽是 1.5，Lucide、Tabler、Feather 是 2。**同一个界面里最好只用一套**，否则粗细和圆角会对不上。

完整的 23 套实测数据见下表。“只设 color 变色”和“CSS 改线宽”两列是在 Chromium 里实际渲染、数像素得出来的，具体做法在下一小节讲。

<figure class="dd dd-figure dt-figure">
<div class="dt-panel">
<div class="dt-title" id="svr-icons-title">23 套图标库实测（2026-10-28 npm 最新版）</div>
<div class="dt-scroll">
<table class="dt dt-sticky" aria-labelledby="svr-icons-title">
<colgroup><col style="width:20%"><col><col><col><col><col></colgroup>
<thead>
<tr><th scope="col">图标库</th><th scope="col">许可</th><th scope="col">数量（主样式）</th><th scope="col">网格 · 画法</th><th scope="col">只设 color 变色</th><th scope="col">CSS 改线宽</th></tr>
</thead>
<tbody>
<tr class="dt-group"><th colspan="6" scope="rowgroup">描边</th></tr>
<tr><th scope="row">Lucide</th><td>ISC</td><td class="num mono">2,176</td><td class="mono">24 · 线宽 2</td><td class="good">能</td><td class="good">能（墨量 −49%）</td></tr>
<tr><th scope="row">Tabler</th><td>MIT</td><td class="num mono">5,203</td><td class="mono">24 · 线宽 2</td><td class="good">能</td><td class="good">能（−45%）</td></tr>
<tr><th scope="row">Feather</th><td>MIT</td><td class="num mono">287</td><td class="mono">24 · 线宽 2</td><td class="good">能</td><td class="good">能（−49%）</td></tr>
<tr><th scope="row">Heroicons</th><td>MIT</td><td class="num mono">324</td><td class="mono">24 · 线宽 1.5</td><td class="good">能</td><td class="good">能（−33%）</td></tr>
<tr><th scope="row">Iconoir</th><td>MIT</td><td class="num mono">1,383</td><td class="mono">24 · 线宽 1.5</td><td class="good">能</td><td class="good">能（−33%）</td></tr>
<tr><th scope="row">IconPark</th><td>Apache-2.0</td><td class="num mono">2,658</td><td class="mono">48 · 线宽 4</td><td class="good">能</td><td class="bad">不能</td></tr>
<tr><th scope="row">Ionicons</th><td>MIT</td><td class="num mono">1,357</td><td class="mono">512 · 混合</td><td class="good">能</td><td class="bad">不能</td></tr>
<tr class="dt-group"><th colspan="6" scope="rowgroup">填充</th></tr>
<tr><th scope="row">Phosphor</th><td>MIT</td><td class="num mono">1,512 × 6 字重</td><td class="mono">256</td><td class="good">能</td><td>—</td></tr>
<tr><th scope="row">Remix Icon</th><td class="warn">自定义（2026 起）</td><td class="num mono">3,229</td><td class="mono">24</td><td class="good">能</td><td>—</td></tr>
<tr><th scope="row">Bootstrap Icons</th><td>MIT</td><td class="num mono">2,078</td><td class="mono">16</td><td class="good">能</td><td>—</td></tr>
<tr><th scope="row">Font Awesome Free</th><td class="warn">CC BY 4.0</td><td class="num mono">2,883</td><td class="mono">512</td><td class="good">能</td><td>—</td></tr>
<tr><th scope="row">Ant Design</th><td>MIT</td><td class="num mono">848</td><td class="mono">1024</td><td class="good">能</td><td>—</td></tr>
<tr><th scope="row">game-icons</th><td class="warn">CC BY 3.0</td><td class="num mono">4,134</td><td class="mono">512</td><td class="good">能</td><td>—</td></tr>
<tr><th scope="row">Material Symbols</th><td>Apache-2.0</td><td class="num mono">7,874</td><td class="mono">960</td><td class="bad">不能</td><td>—</td></tr>
<tr><th scope="row">MDI</th><td>Apache-2.0</td><td class="num mono">7,447</td><td class="mono">24</td><td class="bad">不能</td><td>—</td></tr>
<tr><th scope="row">Carbon</th><td>Apache-2.0</td><td class="num mono">2,638</td><td class="mono">32</td><td class="bad">不能</td><td>—</td></tr>
<tr><th scope="row">Fluent UI</th><td>MIT</td><td class="num mono">20,786</td><td class="mono">16–48 多尺寸</td><td class="bad">不能</td><td>—</td></tr>
<tr><th scope="row">Octicons</th><td>MIT</td><td class="num mono">784</td><td class="mono">16 / 24</td><td class="bad">不能</td><td>—</td></tr>
<tr><th scope="row">Simple Icons（品牌）</th><td>CC0 · 商标另算</td><td class="num mono">3,467</td><td class="mono">24</td><td class="bad">不能</td><td>—</td></tr>
<tr class="dt-group"><th colspan="6" scope="rowgroup">彩色 emoji</th></tr>
<tr><th scope="row">Fluent Emoji Flat</th><td>MIT</td><td class="num mono">3,174</td><td class="mono">32</td><td colspan="2">颜色写死，不参与改色</td></tr>
<tr><th scope="row">Noto Emoji</th><td>Apache-2.0</td><td class="num mono">3,819</td><td class="mono">128</td><td colspan="2">颜色写死</td></tr>
<tr><th scope="row">Twemoji</th><td class="warn">CC BY 4.0</td><td class="num mono">4,169</td><td class="mono">36</td><td colspan="2">颜色写死</td></tr>
<tr><th scope="row">OpenMoji</th><td class="warn">CC BY-SA 4.0</td><td class="num mono">4,579</td><td class="mono">72</td><td colspan="2">颜色写死</td></tr>
</tbody>
</table>
</div>
<p class="dt-note">数量只算一种样式：Tabler 只算 outline，Material Symbols 只算 outlined（含 -fill 变体），Fluent UI 是全部尺寸的文件数。“不能”变色的那几套，补一行 CSS 就能变，见下文。</p>
</div>
<figcaption>图 5 · 23 套图标库里，有 6 套“只设 color 不变色”，只有 5 套能用 CSS 改线宽</figcaption>
</figure>

### 现象：图标不跟着文字变色

开头那个房子图标怎么设 `color` 都不变色，是因为用的是 `<img src="house.svg">`。我们在 Chromium 里做了一个实验：外层容器写 `color: #ad4f36`，把每套的房子图标分别用 `<img>` 和直接内联两种方式放进去，截图后数红色像素的比例。

结果分成三种：

1. **`<img>` 引用**：23 套全部是黑色，0% 变色。
2. **内联，文件里写了 `currentColor`**：Lucide、Tabler、Phosphor、Remix、Font Awesome 等 13 套 100% 变色。
3. **内联，文件里没写颜色**：Material Symbols、MDI、Carbon、Fluent UI、Octicons、Simple Icons 6 套，依然是黑色。

### 原因

<figure class="dd dd-figure">
<div class="dd-scroll">
<svg class="dd-svg" viewBox="0 0 800 300" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="svr-color-title svr-color-desc">
<title id="svr-color-title">图标能不能跟着文字变色</title>
<desc id="svr-color-desc">用 img 引用的 SVG 是独立文档，页面 CSS 进不去，图标保持黑色；内联且写了 stroke 等于 currentColor 的图标取外层 color，变成红色；内联但没写 fill 的图标默认黑色，补一行 svg 的 fill 等于 currentColor 才变色。</desc>
<defs>
<marker id="svr-color-arrow" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto"><path class="dd-head" d="M1 1 L7 4 L1 7"/></marker>
</defs>
<style>
.dd-svg .svr-st-ink{fill:none;stroke:var(--dd-ink);stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.dd-svg .svr-st-acc{fill:none;stroke:var(--dd-accent);stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.dd-svg .svr-f-ink{fill:var(--dd-ink)}
.dd-svg .svr-f-acc{fill:var(--dd-accent)}
</style>
<rect class="dd-frame" width="800" height="300" rx="10"/>
<rect class="dd-zone" x="16" y="16" width="248" height="268" rx="8"/>
<rect class="dd-zone" x="276" y="16" width="248" height="268" rx="8"/>
<rect class="dd-zone" x="536" y="16" width="248" height="268" rx="8"/>
<text class="t-zone" x="32" y="44">① 用 &lt;img&gt; 引用</text>
<text class="t-zone" x="292" y="44">② 内联，写了 currentColor</text>
<text class="t-zone" x="552" y="44">③ 内联，没写 fill</text>
<path class="dd-edge" d="M638 180 H674" marker-end="url(#svr-color-arrow)"/>
<rect class="dd-card" x="32" y="60" width="216" height="80" rx="6"/>
<text class="t-mono" x="44" y="84">&lt;img src="house.svg"&gt;</text>
<text class="t-val" x="44" y="106">.nav {</text>
<text class="t-val" x="44" y="126">  color: #ad4f36; }</text>
<rect class="dd-card" x="292" y="60" width="216" height="80" rx="6"/>
<text class="t-mono" x="304" y="84">&lt;svg fill="none"</text>
<text class="t-mono" x="304" y="106">  stroke="<tspan class="t-acc">currentColor</tspan>"&gt;</text>
<text class="t-val" x="304" y="126">.nav { color: #ad4f36; }</text>
<rect class="dd-card" x="552" y="60" width="216" height="80" rx="6"/>
<text class="t-mono" x="564" y="84">&lt;svg viewBox="0 0 24 24"&gt;</text>
<text class="t-mono" x="564" y="106">  &lt;path d="M12 3L2 12…"/&gt;</text>
<text class="t-mono" x="564" y="126"><tspan class="t-acc">svg { fill: currentColor }</tspan></text>
<svg x="116" y="156" width="48" height="48" viewBox="0 0 24 24"><path class="svr-st-ink" d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8"/><path class="svr-st-ink" d="M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>
<svg x="376" y="156" width="48" height="48" viewBox="0 0 24 24"><path class="svr-st-acc" d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8"/><path class="svr-st-acc" d="M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>
<svg x="584" y="156" width="48" height="48" viewBox="0 0 24 24"><path class="svr-f-ink" d="M12 5.69L17 10.19V18H15V12H9V18H7V10.19L12 5.69M12 3L2 12H5V20H11V14H13V20H19V12H22"/></svg>
<svg x="688" y="156" width="48" height="48" viewBox="0 0 24 24"><path class="svr-f-acc" d="M12 5.69L17 10.19V18H15V12H9V18H7V10.19L12 5.69M12 3L2 12H5V20H11V14H13V20H19V12H22"/></svg>
<text class="t-note" x="140" y="228" text-anchor="middle">23 套全部不变色</text>
<text class="t-note" x="400" y="228" text-anchor="middle">Lucide、Tabler、Remix 等 13 套</text>
<text class="t-note" x="608" y="228" text-anchor="middle">补 CSS 前</text>
<text class="t-note" x="712" y="228" text-anchor="middle">补 CSS 后</text>
<text class="t-say" x="32" y="256">图片是独立文档，</text>
<text class="t-say" x="32" y="274">页面的 CSS 进不去</text>
<text class="t-say" x="292" y="256">currentColor 取的就是</text>
<text class="t-say" x="292" y="274">外层元素的 color</text>
<text class="t-say" x="552" y="256">没写 fill 时默认黑色，</text>
<text class="t-say" x="552" y="274">Material、MDI 等 6 套如此</text>
</svg>
</div>
<figcaption>图 6 · 图标能不能跟着文字变色，取决于引用方式和文件里有没有写 currentColor</figcaption>
</figure>

`<img>` 引用的 SVG 是一个独立的文档，页面上的 CSS 进不到它里面去，所以第一种情况无论怎么写都不会变色，想换颜色只能换文件，或者改用 CSS 的 `mask-image`。内联以后，SVG 成了页面 DOM 的一部分，`currentColor` 这个关键字取的就是外层元素的 `color` 值[^currentcolor]。至于第三种，文件里压根没有 `fill` 属性，按 SVG 的默认值就是黑色；它并不是“改不了”，只是要在页面里补一行 `svg { fill: currentColor }`，补上以后同样 100% 变色。

### 线宽和体积

描边图标还有一个好处：**线宽可以用 CSS 改**。我们给内联的 svg 根元素加了一行 `stroke-width: 1`，再数一次墨量：Lucide、Feather 少了 49%，Tabler 少了 45%，Heroicons 和 Iconoir 少了 33%，图标都变细了。IconPark 和 Ionicons 却没有变化，因为它们把 `stroke-width` 写在了内部的 `<g>` 或 `<path>` 上，内部元素自己的属性优先于从根元素继承来的值。

单个图标的体积都很小。Feather 平均 379 字节，Lucide 485 字节，Tabler 559 字节，用 svgo 再压一次能少 10% 到 40%。Font Awesome 每个文件多出一行许可注释，平均 920 字节；这行注释正好满足了 CC BY 的署名要求，压缩时别把它删掉。

### 怎么选

如果界面需要跟着主题变色、还想统一调线宽，描边的 Lucide[^lucide] 和 Tabler[^tabler] 最省心：许可宽松，数量够多，文件就是纯 SVG，不依赖任何前端框架，Go 的模板里直接内联也行。需要多种粗细的，Phosphor 一套六种字重[^phosphor]；需要和 Android、Google 系产品风格一致的，选 Material Symbols[^material]，记得补那行 `fill: currentColor`。品牌 logo 用 Simple Icons，文件是 CC0，但 logo 本身是各家的商标，只能用来指代那个品牌[^simpleicons]。Font Awesome Free[^fontawesome] 和 game-icons[^gameicons] 是 CC BY，用了就要署名。

给 AI 当参照，也是描边图标库最合适：它的规格就是几个数字（24 网格、线宽 2、圆角线端），量得出来，也查得出来。第八节就用 Lucide 做这件事。

图标和插画之外，网页上还有一类 SVG 用得很多：背景。

## 五、图案与背景

背景图案有两种来源。一种是现成的平铺图案，代表是 Hero Patterns：87 个图案，每个都是一个只有一种填充色 `#000` 的 path，中位数 485 字节[^heropatterns]。网站上选好前景色和背景色以后，它做的事情就是把 `#000` 换成你选的颜色，再整段塞进 CSS 的 `background-image: url("data:image/svg+xml,…")`。最大的 Topography 图案也只有 91,567 字节。它的许可是 CC BY 4.0，使用时要署名[^ccby]。

另一种是生成器。Haikei 能现场生成波浪、斑点、分层山峰等背景，免费且不用注册，但我们没找到它单独的许可页[^haikei]；fffuel 的一系列生成器明确写了生成的图片可以商用、不用署名，只是不能把图片本身拿去转售或再分发[^fffuel]；SVG Backgrounds 的免费素材要署名，订阅后才能去掉[^svgbackgrounds]。

生成器和现成素材相比，有个不显眼的好处：每次输出的都不一样，不会出现“三个网站用着同一张背景”的撞图。

## 六、聚合站与开放图库

前面几节的资源都来自“一个作者或一个团队画的一套”。当这些套里都找不到想要的图时，就会用到聚合站，而聚合站的问题前面已经看到了：许可要逐个看。

- **Iconify**：244 套、41 万多个图标，每套都有明确的许可字段，搜索时可以按许可筛选，也可以通过 API 直接取 SVG[^iconify]。它的周边工具 Icônes 是一个很好用的检索界面。
- **SVG Repo**：图标和插画混在一起，每个文件页标着自己的许可，默认不要求署名，但不同作者的条款不同[^svgrepo]。我们用脚本访问它的许可页和首页，都收到了 429（请求过多），它显然不欢迎批量下载。
- **iconfont.cn**：国内用得最多的图标平台，图标由用户上传。vuepress-theme-hope 的文档专门提醒：商用项目要获得作者授权，上传者也可能上传了版权属于第三方的图标[^themehope]。它的授权说明页需要登录才能看到，我们没能核对原文。
- **Openclipart**：18 万多幅矢量图，全部放入公有领域[^openclipart]。风格不统一，而且大多是 Inkscape 导出的文件，带着大量编辑器元数据：前面表里那张 iso-house 有 359.5 KB、981 个 id，svgo 一压就去掉了一半。
- **Wikimedia Commons**：每个文件的许可不同。Linux 的企鹅 Tux 要求注明作者 Larry Ewing[^commons]。

像 Openclipart 这样的文件不止体积大。它和 Tux 里那上百个 id，被几十个渐变和滤镜引用着，把它们直接内联进页面时，还会碰到一个看不见的坑。

## 七、放进页面之前的处理

### 现象

我们做了这样一个实验：在同一个页面里先内联那张 unDraw 的 business-chart，再内联一个用 svgo 压缩过的 Tux，然后和单独渲染的 Tux 逐像素比较。结果有 1,674 个像素不一样，企鹅脚掌的阴影没了。

### 原因

<figure class="dd dd-figure">
<div class="dd-scroll">
<svg class="dd-svg" viewBox="0 0 800 328" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="svr-id-title svr-id-desc">
<title id="svr-id-title">两张内联 SVG 的 id 冲突</title>
<desc id="svr-id-desc">页面里先出现 unDraw 插画的 linearGradient id a，再出现 Tux 的 linearGradient id a。Tux 的另一个渐变 ac 通过 xlink:href 指向 #a，浏览器按文档顺序取到了 unDraw 的灰色渐变，Tux 脚掌的阴影因此丢失。加上 prefixIds 后 id 改名，差异为 0。</desc>
<defs>
<marker id="svr-id-arrow-acc" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto"><path class="dd-head-acc" d="M1 1 L7 4 L1 7"/></marker>
</defs>
<rect class="dd-frame" width="800" height="328" rx="10"/>
<rect class="dd-zone" x="16" y="16" width="768" height="296" rx="8"/>
<text class="t-zone" x="40" y="44">同一个页面的 DOM：先内联 unDraw，再内联 svgo 压过的 Tux</text>
<path class="dd-edge-acc" d="M440 161 H408 Q400 161 400 153 V117 Q400 109 392 109 H362" marker-end="url(#svr-id-arrow-acc)"/>
<rect class="dd-card" x="40" y="64" width="320" height="110" rx="6"/>
<path class="dd-card-head" d="M40 70 Q40 64 46 64 H354 Q360 64 360 70 V96 H40 Z"/>
<text class="t-name" x="56" y="85">第 1 张 · unDraw</text>
<text class="t-mono" x="344" y="85" text-anchor="end">business-chart</text>
<text class="t-mono" x="56" y="113">&lt;linearGradient <tspan class="t-acc">id="a"</tspan>&gt;</text>
<line class="dd-hair" x1="40" y1="122" x2="360" y2="122"/>
<text class="t-val" x="56" y="139">stop-color="gray"</text>
<line class="dd-hair" x1="40" y1="148" x2="360" y2="148"/>
<text class="t-val" x="56" y="165">stop-opacity="0.251"</text>
<rect class="dd-card" x="440" y="64" width="320" height="136" rx="6"/>
<path class="dd-card-head" d="M440 70 Q440 64 446 64 H754 Q760 64 760 70 V96 H440 Z"/>
<text class="t-name" x="456" y="85">第 2 张 · Tux</text>
<text class="t-mono" x="744" y="85" text-anchor="end">svgo 后</text>
<text class="t-val" x="456" y="113">&lt;linearGradient id="a"&gt;</text>
<text class="t-note" x="744" y="113" text-anchor="end">后出现，没人用到</text>
<line class="dd-hair" x1="440" y1="122" x2="760" y2="122"/>
<text class="t-mono" x="456" y="139">&lt;linearGradient id="ac"</text>
<line class="dd-hair" x1="440" y1="148" x2="760" y2="148"/>
<text class="t-mono" x="456" y="165">  xlink:href="<tspan class="t-acc">#a</tspan>"&gt;</text>
<text class="t-note" x="744" y="165" text-anchor="end">继承 a 的色标</text>
<line class="dd-hair" x1="440" y1="174" x2="760" y2="174"/>
<text class="t-mono" x="456" y="191">fill="url(#ac)"</text>
<text class="t-note" x="744" y="191" text-anchor="end">脚掌</text>
<text class="t-say" x="40" y="236">一个页面只有一个 id 命名空间，#a 按文档顺序找到的是第一张图里的那个 a。</text>
<text class="t-say" x="40" y="258">svgo 会把 id 缩短成 a、b、c，压过的两张图几乎一定撞名。</text>
<text class="t-mono" x="40" y="292">与单独渲染相比：1,674 个像素不同　→　加 prefixIds 后（id 变成 tux__…）：0 个</text>
</svg>
</div>
<figcaption>图 7 · 两张内联 SVG 里都有 id="a"，后一张的引用会指到前一张去</figcaption>
</figure>

SVG 内联以后，它的 id 和页面上其他元素共用一个命名空间。Tux 里有个渐变 `ac`，自己不写色标，而是用 `xlink:href="#a"` 继承渐变 `a` 的色标；浏览器按文档顺序找 `#a`，先找到的是 unDraw 那张图里的灰色半透明渐变，于是脚掌的金黄色阴影变成了几乎透明的灰。

更麻烦的是，这个冲突往往是“压缩”造成的。unDraw 的文件本身就只有一个 `id="a"`；svgo 默认会把 id 缩短成 a、b、c 这样的短名，两张都压过的图放在一起，几乎一定撞名。

### 解决

svgo 有一个 `prefixIds` 插件，给每个文件的 id 和引用统一加上前缀[^svgo]。给 Tux 加上前缀 `tux` 再做同样的实验，差异是 0 个像素。另一种办法是退回 `<img>` 引用：图片是独立文档，id 互不干扰，代价是上一节说的不能跟着文字变色。

所以一张下载来的 SVG 放进页面之前，大致要过三关：用 svgo 去掉编辑器元数据（Sketch、Inkscape 导出的文件通常能少一半，unDraw 这种已经很干净的只少 12%–19%）；内联时加 id 前缀；有深色模式的站，再把关键颜色换成 CSS 类。

交给 AI 之前，第一关同样要过。Humaaans 那张 79.6 KB 的原文件，按每 3–4 个字符一个 token 粗估要两万多 token，其中大半是图层名和编辑器元数据，对“学风格”毫无帮助；压过以后是 31.0 KB。图标就没有这个问题，一个 Lucide 图标不到 500 字节。

文件处理干净了，最后回到开头的目的：怎么把这些 SVG 交给 AI，让它画得更好。

## 八、给 AI 画图找参照

### 参照不是素材

先做一个最直接的尝试：让 Claude “按 Lucide 的风格画一个云上传图标”。它给出的三条路径里，箭头的两条 `M12 13v8`、`m8 17 4-4 4 4` 和 Lucide 自带的 cloud-upload 一字不差，云朵轮廓也只差在小数位（`4.2 15.1` 对 `4 14.899`）。

为什么会这样？Lucide 这类热门开源图标库在网上被转载过无数次，模型早就“记住”了它们。要画的东西参照库里已经有，AI 交出来的就是复刻，不是新画的。

这说明了两件事。第一，**搜到现成的就直接用**：许可允许，现成的图标总比重画的好，不必让 AI 再画一遍。第二，只有参照库里没有的东西才需要 AI 画，而这时参照的作用是给出 baseline，不是提供素材：网格、线宽、圆角和留白向它看齐，画完以后拿它来对照，形状要是新的。

### 边搜边用

参照最好不是事先备好的一个文件夹，而是**画什么就搜什么**。以“一张图片挂着许可吊牌”这个图标为例，Lucide 里没有现成的，于是让 AI 先把它拆成单个名词：图片、吊牌、许可，再到同一套图标里一个个搜。

搜索用的是 Iconify 的接口[^iconifysearch]，它能把搜索限定在一套图标里，还能返回这套图标的许可。我们把它包成一个十几行的脚本 `svg-refs.mjs`，AI 在终端里跑一行命令就能拿到参照：

```text
$ node svg-refs.mjs lucide image tag license
# Lucide，许可 ISC，网格 24

## image → image（共 11 个结果）
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15l-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/></g></svg>

## tag → tag（共 4 个结果）
<svg …>…<circle cx="7.5" cy="7.5" r=".5" fill="currentColor"/></g></svg>

## license：没有搜到
```

有两个细节是实际搜了才知道的。一是要按单个词搜：直接搜 “image tag” 一个结果都没有，拆开以后两个词都能搜到。二是 license 在 Lucide 里没有，在 Tabler 里有。这时不要跨库去补，两套图标的线宽和圆角不同，混在一起当参照，AI 学到的风格反而是乱的。

搜到的参照要怎么用，整个流程如下：

<figure class="dd dd-figure">
<div class="dd-scroll">
<svg class="dd-svg" viewBox="0 0 800 300" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="svr-ai-flow-title svr-ai-flow-desc">
<title id="svr-ai-flow-title">边搜参照边画图的流程</title>
<desc id="svr-ai-flow-desc">把要画的东西拆成图片、吊牌、许可三个词，在 Lucide 里各搜一次，搜到 image 和 tag 两个图标，从中量出一份 baseline 规格，写进 prompt 交给 Claude 生成；输出先用按同一份 baseline 写的脚本检查，再和参照并排渲染对照，差距写成具体的话回到 prompt。</desc>
<defs>
<marker id="svr-ai-arrow" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto"><path class="dd-head" d="M1 1 L7 4 L1 7"/></marker>
<marker id="svr-ai-arrow-acc" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto"><path class="dd-head-acc" d="M1 1 L7 4 L1 7"/></marker>
</defs>
<style>
.dd-svg .svr-ai-ic{color:var(--dd-ink);fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
</style>
<rect class="dd-frame" width="800" height="300" rx="10"/>
<rect class="dd-zone" x="16" y="16" width="168" height="268" rx="8"/>
<rect class="dd-zone" x="200" y="16" width="200" height="268" rx="8"/>
<rect class="dd-zone" x="416" y="16" width="176" height="268" rx="8"/>
<rect class="dd-zone" x="608" y="16" width="176" height="268" rx="8"/>
<text class="t-zone" x="32" y="44">① 按元素搜参照</text>
<text class="t-zone" x="216" y="44">② 量出 baseline</text>
<text class="t-zone" x="432" y="44">③ 生成</text>
<text class="t-zone" x="624" y="44">④ 对照</text>
<path class="dd-edge" d="M176 158 H208" marker-end="url(#svr-ai-arrow)"/>
<path class="dd-edge-acc" d="M384 82 H424" marker-end="url(#svr-ai-arrow-acc)"/>
<path class="dd-edge" d="M504 100 V124" marker-end="url(#svr-ai-arrow)"/>
<path class="dd-edge" d="M504 160 V180" marker-end="url(#svr-ai-arrow)"/>
<path class="dd-edge" d="M536 208 H616" marker-end="url(#svr-ai-arrow)"/>
<path class="dd-edge dd-dash" d="M624 82 H584" marker-end="url(#svr-ai-arrow)"/>
<svg class="svr-ai-ic" x="40" y="64" width="44" height="44" viewBox="0 0 24 24"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/></svg>
<text class="t-mono" x="100" y="84">image</text>
<text class="t-note" x="100" y="102">图片 → 1 个</text>
<svg class="svr-ai-ic" x="40" y="132" width="44" height="44" viewBox="0 0 24 24"><path d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z"/><circle cx="7.5" cy="7.5" r=".5" fill="currentColor"/></svg>
<text class="t-mono" x="100" y="152">tag</text>
<text class="t-note" x="100" y="170">吊牌 → 1 个</text>
<rect class="dd-derived" x="40" y="200" width="44" height="44" rx="6"/>
<text class="t-mono" x="100" y="220">license</text>
<text class="t-note" x="100" y="238">许可 → 没有</text>
<rect class="dd-card" x="216" y="64" width="168" height="188" rx="6"/>
<path class="dd-card-head" d="M216 70 Q216 64 222 64 H378 Q384 64 384 70 V96 H216 Z"/>
<text class="t-name t-acc" x="232" y="85">风格规格</text>
<text class="t-mono" x="232" y="113">viewBox 0 0 24 24</text>
<line class="dd-hair" x1="216" y1="122" x2="384" y2="122"/>
<text class="t-mono" x="232" y="139">stroke-width 2</text>
<line class="dd-hair" x1="216" y1="148" x2="384" y2="148"/>
<text class="t-mono" x="232" y="165">linecap round</text>
<line class="dd-hair" x1="216" y1="174" x2="384" y2="174"/>
<text class="t-mono" x="232" y="191">几何落在 2–22</text>
<line class="dd-hair" x1="216" y1="200" x2="384" y2="200"/>
<text class="t-mono" x="232" y="217">元素 2–5 个</text>
<line class="dd-hair" x1="216" y1="226" x2="384" y2="226"/>
<text class="t-mono" x="232" y="243">交叠处留 2</text>
<rect class="dd-card" x="432" y="64" width="144" height="36" rx="6"/>
<text class="t-name" x="448" y="87">prompt</text>
<text class="t-val" x="560" y="87" text-anchor="end">规格+参照</text>
<rect class="dd-card" x="432" y="124" width="144" height="36" rx="6"/>
<text class="t-name" x="448" y="147">Claude</text>
<text class="t-val" x="560" y="147" text-anchor="end">写 SVG</text>
<svg class="svr-ai-ic" x="472" y="184" width="48" height="48" viewBox="0 0 24 24"><path d="M17 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h5"/><circle cx="7.5" cy="11.5" r="1.5"/><path d="m17 19-2.586-2.586a2 2 0 0 0-2.828 0L8 21"/><path d="M21 3v4.172a2 2 0 0 1-.586 1.414l-3.5 3.5a1.5 1.5 0 0 1-2.121 0l-1.879-1.879a1.5 1.5 0 0 1 0-2.121l3.5-3.5A2 2 0 0 1 17.828 3z"/><circle cx="17.5" cy="6.5" r=".5" fill="currentColor"/></svg>
<text class="t-note" x="504" y="256" text-anchor="middle">第 3 轮的输出</text>
<rect class="dd-card" x="624" y="64" width="144" height="36" rx="6"/>
<text class="t-name" x="640" y="87">并排渲染</text>
<text class="t-val" x="752" y="87" text-anchor="end">肉眼对照</text>
<rect class="dd-card" x="624" y="124" width="144" height="128" rx="6"/>
<path class="dd-card-head" d="M624 130 Q624 124 630 124 H762 Q768 124 768 130 V156 H624 Z"/>
<text class="t-mono" x="640" y="145">check-icon.cjs</text>
<text class="t-val" x="640" y="173">✓ 根元素 6 项</text>
<line class="dd-hair" x1="624" y1="182" x2="768" y2="182"/>
<text class="t-val" x="640" y="199">✓ 无 id、defs</text>
<line class="dd-hair" x1="624" y1="208" x2="768" y2="208"/>
<text class="t-val" x="640" y="225">✓ 5 个元素</text>
<line class="dd-hair" x1="624" y1="234" x2="768" y2="234"/>
<text class="t-val" x="640" y="248">✓ x 3–21 y 3–21</text>
<text class="t-say" x="32" y="276">虚线：这套里没有</text>
<text class="t-say" x="216" y="276">同一份规格写进 prompt，也是第四步检查的标准</text>
</svg>
</div>
<figcaption>图 8 · 画什么就搜什么：搜到的参照给出 baseline，写进 prompt，也拿来验收输出</figcaption>
</figure>

### prompt 的写法

拿到参照以后，prompt 要回答四个问题：参照是什么、从参照里学什么、画什么、画完怎么验收。下面是这个例子实际用的 prompt：

```text
你要用 SVG 代码画一个 24×24 的界面图标：一张图片（方框里有太阳和山），
右上角挂着一枚许可吊牌，表示“这张图带授权信息”。Lucide 里没有这个图标。

【一、搜参照】
1. 把要画的东西拆成单个名词：image、tag、license。
2. 在同一套图标里搜：node svg-refs.mjs lucide image tag license
3. 只用搜到的结果。某个词没搜到，不要去别的图标库补。
4. 参照只用来对齐风格和质量：网格、线宽、圆角、留白、元素数量。
   不要复用参照的形状，交付的必须是新的组合。

【二、先量规格，写出来再画】
从参照里量出并写下：viewBox、线宽、线端和拐角、图形占用的范围、
元素个数、两个图形交叠时怎么处理、小圆点怎么画。

【三、画】
- 根元素只写 xmlns、viewBox 和描边属性，不写 width/height
- 不写 id、class、style；不用 defs、渐变、滤镜、image、text
- 颜色只用 currentColor
- 只输出一段 <svg>…</svg>

【四、对照】
运行 node check-icon.cjs out.svg；再把输出和参照并排渲染成 PNG，
线与线的间距、图形的轻重要和参照一致。不一致就写出具体差距，再改一版。
```

第二步要求 AI 先把规格写出来，是因为“学风格”太含糊。这一次 Claude 写下的规格是：viewBox 0 0 24 24；`fill="none"`、`stroke-width="2"`、线端和拐角都是圆的；几何落在 2–22 之间；转角半径 2；2–5 个元素；两个图形交叠时，下层的线断开、留出约 2 的空隙；小圆点用 `r=".5"` 加实心填充（照 tag 的孔）。写出来的规格就是 baseline，既约束这一次的绘制，也是第四步检查的标准。

### 渲染对照

第一轮的输出能通过规格检查，但和参照放在一起渲染，问题就出来了：

<figure class="dd dd-figure">
<div class="dd-scroll">
<svg class="dd-svg" viewBox="0 0 800 268" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="svr-ai-iter-title svr-ai-iter-desc">
<title id="svr-ai-iter-title">参照图标和两轮生成结果</title>
<desc id="svr-ai-iter-desc">左边是搜到的两个参照：Lucide 的 image 和 tag；中间是第 1 轮生成的“带许可吊牌的图片”，吊牌下角和山的斜线挤在一起；右边是第 3 轮，吊牌缩小、边框断开，线与线之间都留出了空隙。两轮都通过了脚本检查。</desc>
<style>
.dd-svg .svr-ai-ic2{color:var(--dd-ink);fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
</style>
<rect class="dd-frame" width="800" height="268" rx="10"/>
<rect class="dd-zone" x="16" y="16" width="352" height="236" rx="8"/>
<rect class="dd-zone" x="384" y="16" width="192" height="236" rx="8"/>
<rect class="dd-zone" x="592" y="16" width="192" height="236" rx="8"/>
<text class="t-zone" x="32" y="44">搜到的参照 · Lucide（ISC，原样）</text>
<text class="t-zone" x="400" y="44">第 1 轮</text>
<text class="t-zone" x="608" y="44">第 3 轮</text>
<svg class="svr-ai-ic2" x="80" y="68" width="64" height="64" viewBox="0 0 24 24"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/></svg>
<text class="t-mono" x="112" y="160" text-anchor="middle">image</text>
<svg class="svr-ai-ic2" x="224" y="68" width="64" height="64" viewBox="0 0 24 24"><path d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z"/><circle cx="7.5" cy="7.5" r=".5" fill="currentColor"/></svg>
<text class="t-mono" x="256" y="160" text-anchor="middle">tag</text>
<svg class="svr-ai-ic2" x="448" y="68" width="64" height="64" viewBox="0 0 24 24"><path d="M17 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h4"/><circle cx="7.5" cy="12.5" r="1.5"/><path d="m17 19-2.586-2.586a2 2 0 0 0-2.828 0L7 21"/><path d="M21 3v5.172a2 2 0 0 1-.586 1.414l-4.5 4.5a1.5 1.5 0 0 1-2.121 0l-3.379-3.379a1.5 1.5 0 0 1 0-2.121l4.5-4.5A2 2 0 0 1 16.328 3z"/><circle cx="17.5" cy="6.5" r=".5" fill="currentColor"/></svg>
<svg class="svr-ai-ic2" x="656" y="68" width="64" height="64" viewBox="0 0 24 24"><path d="M17 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h5"/><circle cx="7.5" cy="11.5" r="1.5"/><path d="m17 19-2.586-2.586a2 2 0 0 0-2.828 0L8 21"/><path d="M21 3v4.172a2 2 0 0 1-.586 1.414l-3.5 3.5a1.5 1.5 0 0 1-2.121 0l-1.879-1.879a1.5 1.5 0 0 1 0-2.121l3.5-3.5A2 2 0 0 1 17.828 3z"/><circle cx="17.5" cy="6.5" r=".5" fill="currentColor"/></svg>
<circle class="dd-edge-acc dd-dash" cx="482" cy="109" r="14"/>
<text class="t-say" x="400" y="180"><tspan class="t-acc">吊牌下角和山的斜线</tspan></text>
<text class="t-say" x="400" y="200"><tspan class="t-acc">挤在一起</tspan></text>
<text class="t-say" x="608" y="180">吊牌缩小，边框断开，</text>
<text class="t-say" x="608" y="200">线与线之间都留出空隙</text>
<text class="t-note" x="32" y="236">学网格、线宽、圆角和留白，不复用形状</text>
<text class="t-note" x="400" y="236">脚本检查 12 / 12 通过</text>
<text class="t-note" x="608" y="236">脚本检查 12 / 12 通过</text>
</svg>
</div>
<figcaption>图 9 · 两轮都通过了规格检查，拥挤只有和参照并排渲染才看得出来</figcaption>
</figure>

吊牌下角和山的斜线之间的距离不到 1，挤成一团，这在只看代码时是发现不了的。于是把差距写成具体的话交回去：“吊牌缩小到右上角约 9×9 的范围，图片边框在吊牌处断开，山的斜线终点左移，任何两条线之间至少留 2。”第二轮间距正常了，但吊牌上的孔贴着边；第三轮只挪了孔的位置。

检查脚本 `check-icon.cjs` 只有几十行，逐项对照规格：根元素的 6 个描边属性、有没有 id 和 defs、元素个数，以及在浏览器里用 `getBBox` 量出的图形范围。三轮输出都是 12 项全过。拿同一个脚本去查 MDI 的 home-outline，12 项里有 7 项不通过，因为它是另一套“填充”风格的图标。**脚本挡住的是风格跑偏，并排渲染挡住的是质量问题**，两者缺一不可。

### 插画的参照

插画的参照没法这样量得一清二楚，做法要变一变。插画没有 Iconify 这样统一的搜索接口；Openclipart 和 Wikimedia Commons 虽然能搜，许可也写在每个文件上，但我们从云端调 Wikimedia 的接口，第一次请求就收到了 429。更实际的办法是事先备一小批许可宽松、颜色少的插画（比如 Open Doodles、Open Peeps），压缩后存在本地，AI 画图时按文件名搜。

交给 AI 时，参照只给一两张压缩过的小文件，再把风格写成规格：几种颜色、各自管什么（线条、主色、灰阶），线宽多少，构图怎么留白。本站的配图规则 `.claude/skills/blog-diagram/SKILL.md` 就是这样一份规格：配色变量表、样式类名、4px 网格、卡片和行的高度、出图前的检查清单，每次让 AI 画图都会先读它。

## 九、按场景选资源

把前面几节的结论按用途收拢一下：

<figure class="dd dd-figure dt-figure">
<div class="dt-panel">
<div class="dt-title" id="svr-pick-title">按场景选资源</div>
<div class="dt-scroll">
<table class="dt" aria-labelledby="svr-pick-title">
<colgroup><col style="width:24%"><col style="width:34%"><col></colgroup>
<thead>
<tr><th scope="col">要做什么</th><th scope="col">先看</th><th scope="col">理由和注意</th></tr>
</thead>
<tbody>
<tr><th scope="row">文章头图、空状态、落地页</th><td class="acc">unDraw、Open Doodles、Open Peeps</td><td>颜色少，改一个色值就能配上站点主题；后两者 CC0。unDraw 不能批量抓取、不能用于 AI 训练</td></tr>
<tr><th scope="row">需要拼装多样的人物</th><td>Humaaans、Blush</td><td>可拼装，但颜色多，深色模式下要垫底</td></tr>
<tr><th scope="row">界面图标</th><td class="acc">Lucide、Tabler</td><td>描边、currentColor、能改线宽，ISC / MIT</td></tr>
<tr><th scope="row">需要多种字重或 Google 风格</th><td>Phosphor、Material Symbols</td><td>Material 要补 <code>fill: currentColor</code></td></tr>
<tr><th scope="row">品牌 logo</th><td>Simple Icons</td><td>文件 CC0，logo 是商标，只用来指代品牌</td></tr>
<tr><th scope="row">背景纹样</th><td>Hero Patterns、fffuel、Haikei</td><td>Hero Patterns 要署名；生成器不撞图</td></tr>
<tr><th scope="row">找冷门图标</th><td>Iconify（Icônes）</td><td>先按许可筛选，避开 NC 和 SA</td></tr>
<tr><th scope="row">给 AI 画图当参照</th><td class="acc">Lucide、Tabler（按词搜）；Open Doodles、Open Peeps</td><td>规格能量化，许可宽松；避开写了 AI 禁令的 unDraw、DrawKit</td></tr>
<tr><th scope="row">要正规商用、不想看条款</th><td>付费：Storyset / Icons8 订阅</td><td>付费后免署名、给 SVG</td></tr>
</tbody>
</table>
</div>
</div>
<figcaption>图 10 · 按用途选，先定许可，再看文件能不能改成自己的配色</figcaption>
</figure>

回到开头那三个问题。紫色的 unDraw 插画，替换一个色值 `#6c63ff` 就能配上本站的暖色；深色模式下看不见的 Open Peeps 线条，要么垫一块浅色底，要么把 `#000` 换成 CSS 类；`<img>` 引用的房子图标不变色，是因为图片是独立文档，换成内联、再确认文件里有 `currentColor` 就好。

至于本站的配图，还是会继续让 AI 来画。现成素材解决的是“快速有一张好看的图”，而本站的头图要按文章内容定风格、要跟着深色模式切换、要配上文中的真实数字，这三件事现成素材都做不到。找来的 SVG 在这里的角色是参照：画什么就搜什么，搜到现成的、许可允许就直接用；搜不到，就把搜到的近邻当 baseline，让 AI 对齐它的规格画出新的，画完再和它并排对照。

## 小结

1. **SVG 资源分几类？** 插画、图标、图案与背景、聚合站和开放图库四类，评判标准各不相同。
2. **“免费”是什么意思？** 至少六种：CC0、宽松开源、CC BY、相同方式共享、站点自定义许可、免费增值。自定义许可的禁止项（不能再分发、不能 AI 训练、不能当商标）最容易被忽略，许可还会变，要看许可文件本身。给 AI 当参照的素材，避开 unDraw、DrawKit 这类写了 AI 禁令的站。
3. **插画差在哪？** 风格之外，主要差在颜色数和文件冗余。unDraw 一个主色出现 30 次，换一个色值就能改主题；Humaaans 26 种颜色只能进设计软件；写死的黑线在深色模式下对比度只有 1.1:1。
4. **图标为什么有的不变色？** `<img>` 引用的一律不变；内联时写了 `currentColor` 的跟着 `color` 走，没写 fill 的要补 `svg { fill: currentColor }`。描边图标里只有线宽写在根元素上的 5 套能用 CSS 改线宽。
5. **聚合站要注意什么？** 许可按套或按文件看。Iconify 里约 23% 的图标要署名或带附加条款；iconfont.cn 的图标由用户上传，商用要作者授权。
6. **放进页面前做什么？** svgo 压缩；内联时用 `prefixIds` 加 id 前缀，否则两张图里的 `id="a"` 会互相串，实验里 Tux 有 1,674 个像素被改；有深色模式的话把关键颜色换成 CSS 类。
7. **怎么给 AI 当参照？** 参照是 baseline，不是素材。画什么就按单个名词在同一套图标里搜，搜到现成的就直接用；搜不到的才让 AI 画，prompt 里写清参照、先量出规格、再画、再对照。热门图标库 AI 早就记住了，让它画库里已有的东西，交出来的就是复刻。规格检查挡住风格跑偏，并排渲染挡住质量问题。

## 参考资料
