关于 moai-tool-svg
moai-tool-svg 是用于创建和优化 SVG 图形的技能,面向制作图标、插画和可视化内容的开发者与设计师。内容涵盖 SVG 结构、样式、动画、无障碍设计及 SVGO 优化。
主要功能
- 01SVG 形状、路径与文档结构
- 02渐变、滤镜、裁剪与蒙版
- 03可复用符号与精灵图
- 04CSS 和 SMIL 动画模式
- 05SVGO 优化与配置
- 06无障碍支持与响应式缩放
适用场景
- 01制作 SVG 图标和插画
- 02在 React 组件中嵌入 SVG 图形
- 03优化导出的 SVG 文件
- 04添加无障碍标签并处理装饰性图像
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ modu-ai/ moai-adk --skill moai-tool-svg安装后在 Claude Code 中输入/moai-tool-svg确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
RETIRED.mdmodules/INDEX.mdsvg-animation.mdsvg-basics.mdsvg-optimization.mdsvg-styling.mdreferences/examples.mdreference.md详细介绍
SVG 创建与优化专家
全面的 SVG 开发,涵盖矢量图形创建、SVGO 优化、图标系统、数据可视化和动画。此技能提供适用于各种 SVG 工作流的模式,从基本形状到复杂动画图形。
快速参考(30 秒)
基本 SVG 模板
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<title>Accessible Title</title>
<desc>Description for screen readers</desc>
</svg>
常见形状速查表
矩形:<rect x="10" y="10" width="80" height="60" rx="5" />
圆形:<circle cx="50" cy="50" r="40" />
椭圆:<ellipse cx="50" cy="50" rx="40" ry="25" />
直线:<line x1="10" y1="10" x2="90" y2="90" stroke="black" />
折线:<polyline points="10,10 50,50 90,10" fill="none" stroke="black" />
多边形:<polygon points="50,10 90,90 10,90" />
路径命令速查
移动命令:
- M x y:移动到绝对位置
- m dx dy:相对移动
- L x y:绘制到绝对位置的直线
- l dx dy:相对绘制直线
- H x:绘制绝对水平线
- h dx:相对绘制水平线
- V y:绘制绝对垂直线
- v dy:相对绘制垂直线
- Z:闭合路径
曲线命令:
- C x1 y1 x2 y2 x y:三次贝塞尔曲线(两个控制点)
- S x2 y2 x y:平滑三次曲线(反射前一个控制点)
- Q x1 y1 x y:二次贝塞尔曲线(一个控制点)
- T x y:平滑二次曲线(反射前一个控制点)
- A rx ry rotation large-arc sweep x y:弧线
SVGO 命令行命令
全局安装:npm install -g svgo
优化单个文件:svgo input.svg -o output.svg
优化目录:svgo -f ./src/icons -o ./dist/icons
显示优化统计信息:svgo input.svg --pretty --indent=2
使用配置文件:svgo input.svg --config svgo.config.mjs
填充和描边速查
填充属性:fill、fill-opacity、fill-rule(nonzero、evenodd)
描边属性:stroke、stroke-width、stroke-opacity、stroke-linecap(butt、round、square)、stroke-linejoin(miter、round、bevel)、stroke-dasharray、stroke-dashoffset
实现指南(5 分钟)
SVG 文档结构
独立文件中的 SVG 元素需要 xmlns 属性。viewBox 将坐标系定义为“minX minY width height”。width 和 height 设置渲染尺寸。
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 200 200"
width="200" height="200"
preserveAspectRatio="xMidYMid meet">
<defs>
<linearGradient id="grad1">
<stop offset="0%" stop-color="#ff0000" />
<stop offset="100%" stop-color="#0000ff" />
</linearGradient>
</defs>
<g id="main-group" transform="translate(10, 10)">
<rect width="100" height="100" fill="url(#grad1)" />
</g>
</svg>
创建可重用符号
符号用于定义可通过 use 元素实例化的可重用图形。符号支持用于缩放的自有 viewBox。
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<symbol id="icon-star" viewBox="0 0 24 24">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>
</symbol>
</defs>
<use href="#icon-star" x="0" y="0" width="24" height="24" />
<use href="#icon-star" x="30" y="0" width="24" height="24" fill="gold" />
<use href="#icon-star" x="60" y="0" width="48" height="48" />
</svg>
路径创建模式
组合移动、直线和曲线的简单图标路径:
<path d="M10 20 L20 10 L30 20 L20 30 Z" />
使用弧线绘制圆角矩形:
<path d="M15 5 H85 A10 10 0 0 1 95 15 V85 A10 10 0 0 1 85 95 H15 A10 10 0 0 1 5 85 V15 A10 10 0 0 1 15 5 Z" />
使用三次贝塞尔曲线绘制心形:
<path d="M50 88 C20 65 5 45 5 30 A15 15 0 0 1 35 30 Q50 45 50 45 Q50 45 65 30 A15 15 0 0 1 95 30 C95 45 80 65 50 88 Z" />
渐变实现
从左到右的线性渐变:
<defs>
<linearGradient id="horizontal-grad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#3498db" />
<stop offset="50%" stop-color="#9b59b6" />
<stop offset="100%" stop-color="#e74c3c" />
</linearGradient>
</defs>
<rect fill="url(#horizontal-grad)" width="200" height="100" />
带焦点的径向渐变:
<defs>
<radialGradient id="sphere-grad" cx="50%" cy="50%" r="50%" fx="30%" fy="30%">
<stop offset="0%" stop-color="#ffffff" />
<stop offset="100%" stop-color="#3498db" />
</radialGradient>
</defs>
<circle fill="url(#sphere-grad)" cx="50" cy="50" r="40" />
SVGO 配置
在项目根目录创建 svgo.config.mjs:
export default {
multipass: true,
plugins: [
'preset-default',
'prefixIds',
{
name: 'sortAttrs',
params: {
xmlnsOrder: 'alphabetical'
}
},
{
name: 'removeAttrs',
params: {
attrs: ['data-name', 'class']
}
}
]
};
保留特定元素的配置:
export default {
multipass: true,
plugins: [
{
name: 'preset-default',
params: {
overrides: {
removeViewBox: false,
cleanupIds: {
preserve: ['icon-', 'logo-']
}
}
}
}
]
};
在 React 中嵌入 SVG
内联 SVG 组件:
const Icon = ({ size = 24, color = 'currentColor' }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none">
<path d="M12 2L2 7l10 5 10-5-10-5z" stroke={color} strokeWidth="2" />
</svg>
);
使用 use 元素的 SVG 雪碧图:
const SpriteIcon = ({ name, size = 24 }) => (
<svg width={size} height={size}>
<use href={`/sprites.svg#${name}`} />
</svg>
);
文本元素
基本文本定位:
<text x="50" y="50" text-anchor="middle" dominant-baseline="middle"
font-family="Arial" font-size="16" fill="#333">
Centered Text
</text>
沿路径排列文本:
<defs>
<path id="text-curve" d="M10 80 Q95 10 180 80" fill="none" />
</defs>
<text font-size="14">
<textPath href="#text-curve">Text following a curved path</textPath>
</text>
高级实现(10 分钟以上)
复杂滤镜效果
带模糊的投影:
<defs>
<filter id="drop-shadow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur in="SourceAlpha" stdDeviation="3" result="blur" />
<feOffset in="blur" dx="3" dy="3" result="offsetBlur" />
<feMerge>
<feMergeNode in="offsetBlur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
发光效果:
<filter id="glow">
<feGaussianBlur stdDeviation="4" result="coloredBlur" />
<feMerge>
<feMergeNode in="coloredBlur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
裁剪与蒙版
用于裁剪的裁剪路径:
<defs>
<clipPath id="circle-clip">
<circle cx="50" cy="50" r="40" />
</clipPath>
</defs>
<image href="photo.jpg" width="100" height="100" clip-path="url(#circle-clip)" />
用于淡出效果的渐变蒙版:
<defs>
<linearGradient id="fade-grad">
<stop offset="0%" stop-color="white" />
<stop offset="100%" stop-color="black" />
</linearGradient>
<mask id="fade-mask">
<rect width="100" height="100" fill="url(#fade-grad)" />
</mask>
</defs>
<rect width="100" height="100" fill="blue" mask="url(#fade-mask)" />
CSS 动画集成
SVG 元素的关键帧动画:
@keyframes pulse {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.1); opacity: 0.8; }
}
.animated-circle {
animation: pulse 2s ease-in-out infinite;
transform-origin: center;
}
描边绘制动画:
.draw-path {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: draw 2s ease forwards;
}
@keyframes draw {
to { stroke-dashoffset: 0; }
}
无障碍最佳实践
对于有意义的图形,始终包含 title 和 desc:
<svg role="img" aria-labelledby="title desc">
<title id="title">Company Logo</title>
<desc id="desc">A blue mountain with snow-capped peak</desc>
</svg>
对于装饰性 SVG,应对屏幕阅读器隐藏:
<svg aria-hidden="true" focusable="false">
</svg>
性能优化
将路径数据精度从 6 位小数降低到 2 位:
之前:M10.123456 20.654321 L30.987654 40.123456
之后:M10.12 20.65 L30.99 40.12
适当情况下,将形状转换为路径以减小文件体积。对重复元素使用符号。应用 SVGZ 压缩,可将体积缩小 20-50%。
有关各主题的详细模式,请参阅 modules 目录。
模块索引
- modules/svg-basics.md:文档结构、坐标系、形状、路径、文本
- modules/svg-styling.md:填充、描边、渐变、图案、滤镜、裁剪、蒙版
- modules/svg-optimization.md:SVGO 配置、压缩、精灵图、性能
- modules/svg-animation.md:CSS 动画、SMIL、JavaScript、交互模式
配合使用效果良好
- moai-domain-frontend:React/Vue SVG 组件集成
- moai-docs-generation:为文档生成 SVG 图表
- moai-domain-uiux:图标系统与设计系统集成
常见借口
| 借口 | 事实 |
|---|---|
| “这个图标用 PNG 就行,SVG 没必要” | PNG 在不同分辨率下会模糊,而且需要准备多个尺寸。SVG 可以完美缩放,对于简单图形来说文件更小。 |
| “我之后再优化 SVG” | 设计工具导出的未优化 SVG 包含编辑器元数据、隐藏图层和精度过高的小数,文件体积会因此膨胀 50-80%。 |
| “内联 SVG 总是比 img 标签好” | 内联 SVG 会增加 HTML 负载,并阻止浏览器缓存。对于不需要动态样式的静态图标,请使用 img 标签。 |
| “装饰性图标不需要考虑无障碍” | 装饰性图标需要设置 aria-hidden=true,才能被屏幕阅读器正确忽略。否则屏幕阅读器会读出无意义的内容。 |
| “SVGO 默认设置适用于所有 SVG” | SVGO 默认设置会移除 viewBox 和 title 元素。要保留无障碍支持和响应式特性,必须进行自定义配置。 |
警示信号
- SVG 文件包含编辑器元数据(Illustrator、Sketch、Figma 导出杂项)
- SVG 缺少 viewBox 属性(会导致响应式缩放失效)
- 交互式 SVG 缺少 role 和 aria-label 属性
- 装饰性 SVG 缺少 aria-hidden="true"
- SVG 文件比视觉效果相同的 PNG 文件更大
验证
- 使用 SVGO 或同类工具优化 SVG(展示优化前后的文件大小)
- 所有 SVG 都存在 viewBox 属性(不能只有固定的 width/height)
- 装饰性 SVG 设置了 aria-hidden="true"
- 交互式 SVG 设置了 role="img" 和 aria-label
- 在目标分辨率下,SVG 文件小于对应的 PNG 文件
- 已提交的 SVG 文件不含编辑器元数据(检查是否含有 Illustrator/Sketch/Figma 标签)