SVG瘦身工具是一款提供了丰富自定义功能的 SVG 压缩工具,遵循 W3C 的 SVG2 规范 (https://www.w3.org/TR/SVG2/) 。
npm install svg-slimming
const svgSlimming = require('svg-slimming');
svgSlimming(svgcode[, config]).then(result => {
console.log(result);
});
其中 svgcode 为字符串格式的 svg 文本,config 为用户自定义的优化配置
优化配置是一个 JSON 格式的对象,其中 key 为对应的配置项,value 为布尔值或数组,当value为数组的时候,第一项为配置开关,后续项为扩展配置参数
下面是一个优化配置的示例:
{
"collapse-g": false,
"combine-transform": [true, 4, 2]
}
- 默认开关:开
- 说明:
- 当 g 元素没有子元素时,移除该元素
- 当 g 元素没有属性值时,用子元素替换该元素
- 当 g 元素只有一个子元素,且自身没有 id、class、mask 属性时,将 g 元素的属性复制到子元素,并用子元素替换之
例如:
<g></g>
<g fill="red"><rect width="100" height="100"/></g>
优化后将变为:
<rect fill="red" width="100" height="100"/>
- 默认开关:开
- 说明:
- 对于所有嵌套的文本容器,当内部文本容器不包含任何有效属性时,移除该元素,并将文本内容提升为父元素的子节点
例如:
<text></text>
<text fill="red"><tspan>123</tspan></text>
优化后将变为:
<text fill="red">123</text>
- 默认开关:开
- 说明:
- 合并满足以下条件的路径节点: 1、所有属性和样式(包括继承样式)相同;2、相邻;3、没有 fill 或 stroke;4、透明度或颜色透明度不小于 1
- 配置参数1:
- 默认值:false
- 遇到 stroke 为空的路径是否进行合并
- 警告,因为没有进行深度的几何解析,合并 fill 不为空的路径可能会导致意外的镂空情况出现!
- 配置参数2:
- 默认值:false
- 是否无视透明度进行合并
例如:
<path d="M0,0L100,100" fill="none" stroke="red" stroke-width="2"/>
<path d="M0,50L100,150" fill="none" stroke="red" stroke-width="2"/>
优化后将变为
<path d="M0,0L100,100M0,50L100,150" fill="none" stroke="red" stroke-width="2"/>
- 默认开关:开
- 说明:
- 分析并合并 transform 属性
- 配置参数1:
- 默认值:3
- 合并后的 matrix 的 a, b, c, d 位置的数值精度,以及 scale 函数的参数精度
- 配置参数2:
- 默认值:1
- 合并后的 matrix 的 e, f 位置的数值精度,以及 translate 函数的参数精度
- 配置参数3:
- 默认值:2
- rotate、skewX、skewY 函数的参数精度
例如:
<rect fill="red" width="100" height="100" transform="translate(100,100)scale(2)rotate(180)"/>
优化后将变为:
<rect fill="red" width="100" height="100" transform="matrix(-2,0,0,-2,100,100)"/>
- 默认开关:开
- 说明:
- 计算 path 的 d 属性,使之变得更短
- 配置参数1:
- 默认值:false
- 应用道格拉斯-普克算法抽稀路径节点
- 配置参数2:
- 默认值:0
- 抽稀节点的阈值
- 配置参数3:(v1.2.9+)
- 默认值:1
- 坐标类型数值的精度
- 配置参数4:(v1.2.9+)
- 默认值:2
- 椭圆弧指令中旋转角度数值的精度
例如:
<path fill="red" d="M0,0L100,0,100,100,0,100z"/>
优化后将变为:
<path fill="red" d="M0,0H100V100H0z"/>
- 默认开关:关
- 说明:
- 对 polygon 和 polyline 应用道格拉斯-普克算法抽稀路径节点
- 配置参数1:
- 默认值:0
- 抽稀节点的阈值
- 默认开关:开
- 说明:
- 移除非规范的属性(不在SVG规范中,且并非xmlns类的属性)
- 配置参数1:
- 默认值:true
- 移除与默认值相同的属性
- 配置参数2:
- 默认值:false
- 保留所有的事件监听属性,目前默认移除
- 配置参数3:
- 默认值:false
- 保留所有的aria属性,目前默认移除
例如:
<rect fill="red" width="100" height="100" aa="1" bb="2" cc="3" aria-autocomplete="both" onclick="console.log('a');"/>
优化后将变为:
<rect fill="red" width="100" height="100"/>
- 默认开关:开
- 说明:
- 移除注释
- 默认开关:开
- 说明:
- 移除 DOCTYPE 声明
rm-hidden
- 默认开关:开
- 说明:
- 移除 display 属性为 none 的元素
- 移除 fill 和 stroke 属性均为 none 的图形类元素
- 移除没有子节点的文本容器
- 移除因某些原因不渲染的图形元素
以下内容将被移除:
display 为 none
<g style="display:none"></g>
stroke 和 fill 均为 none
<rect fill="none" stroke="none" width="100" height="100"/>
circle 元素的 r 属性为 0(其它如:rect 元素的 width 或 height 属性为 0,ellipse 元素的 rx 或 ry 为 0,line 元素的长度为 0 等等)
<circle cx="100" cy="100" r="0"/>
path 元素没有 d 属性或为空(其它如:polyline 和 polygon 元素没有 points 属性或为空等)
<path id="123" />
- 默认开关:开
- 说明:
- 移除不规范嵌套的标签
- 配置参数1:
- 默认值:[]
- 配置忽略该规则的标签
例如:
<rect fill="red" width="100px" height="100px"><circle cx="100" cy="100" r="100"/></rect>
优化后将变为:
<rect fill="red" width="100" height="100"/>
- 默认开关:开
- 说明:
- 移除不在SVG规范内的标签
- 配置参数1:
- 默认值:[]
- 配置忽略该规则的标签
- 默认开关:开
- 说明:
- 移除 px 单位
例如:
<rect fill="red" width="100px" height="100px"/>
优化后将变为:
<rect fill="red" width="100" height="100"/>
- 默认开关:开
- 说明:
- 移除不必要的标签
- 警告!虽然默认并不移除 style 标签,但部分规则(如 shape-to-path)可能会导致样式表中的标签选择器、属性选择器失效!
- 警告!由于并没有对 javascript 脚本进行分析处理,如果默认不移除 script 标签,不能保证优化后的代码仍然可以正确执行!
- 配置参数1:
- 默认值:['desc', 'discard', 'foreignObject', 'video', 'audio', 'iframe', 'canvas', 'metadata', 'script', 'title', 'unknown']
- 配置需要移除的标签名称,只能移除以下列表中的标签:['desc', 'discard', 'foreignObject', 'video', 'audio', 'iframe', 'canvas', 'metadata', 'script', 'style', 'title', 'unknown'];
- 默认开关:开
- 说明:
- 移除 svg 标签的 version 属性
- 默认开关:开
- 说明:
- 当 x、y、width、height 完全相同时,移除 viewBox 属性
例如:
<svg width="1000" height="600" viewBox="0 0 1000 600">
优化后将变为:
<svg width="1000" height="600">
- 默认开关:开
- 说明:
- 移除 xml 声明
- 默认开关:开
- 说明:
- 移除未被引用的 xmlns 定义,移除包含未定义命名空间的属性
例如:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect fill="red" width="100" height="100"/>
</svg>
优化后将变为(由于 xlink 这个 namespace 并没有被引用,所以被移除了):
<svg xmlns="http://www.w3.org/2000/svg">
<rect fill="red" width="100" height="100"/>
</svg>
- 默认开关:开
- 说明:
- 如果形状映射到 path 的结果更短,则使用 path
例如:
<rect fill="red" width="100" height="100"/>
优化后将变为:
<path fill="red" d="M0 0H100V100H0z"/>
- 默认开关:开
- 说明:
- 缩短 className
- 移除不被引用的 className
例如:
<style>.red_rect {fill: red;}</style>
<rect class="red_rect blue_rect" width="100" height="100"/>
优化后将变为:(存在 red_rect 的引用,所以缩短了,不存在 blue_rect 的引用,所以将被移除)
<style>.a {fill: red;}</style>
<rect class="a" width="100" height="100"/>
- 默认开关:开
- 说明:
- 尽可能地缩短颜色定义
- 配置参数1
- 默认值:false
- 是否缩短 rgba、hsla 格式的颜色到 16 进制
- 配置参数2
- 默认值:2
- rgba、hsla 格式的颜色 alpha 值的精度
例如:
<rect fill="#ff0000" stroke="rgb(255,255,255)" width="100" height="100"/>
优化后将变为:
<rect fill="red" stroke="#fff" width="100" height="100"/>
- 默认开关:开
- 说明:
- 缩小数值精度,以获得更好的压缩比
- 配置参数1
- 默认值:1
- 坐标、尺寸类型数值的精度
- 配置参数2
- 默认值:2
- 透明度、角度、弧度等类型数值的精度
例如:
<rect fill="red" width="100.00001" height="100.00001" fill-opacity="0.05999"/>
优化后将变为:
<rect fill="red" width="100" height="100" fill-opacity=".06"/>
- 默认开关:开
- 说明:
- 合并所有的 defs 标签
- 移除无效的 defs 定义
- 移除空的 defs 标签
例如:
<defs>
<circle id="circle-1" fill="#000" cx="60" cy="60" r="60"></circle>
</defs>
<defs>
<circle fill-opacity="0.599999964" fill="#000000" cx="60" cy="60" r="60"></circle>
</defs>
<mask id="mask-2" fill="white">
<use xlink:href="#circle-1" />
</mask>
优化后将变为:
<defs>
<circle id="path-1" fill="#000" cx="60" cy="60" r="60"></circle>
</defs>
<mask id="mask-2" fill="white">
<use xlink:href="#path-1" />
</mask>
- 默认开关:开
- 说明:
- 缩短 ID
- 移除不被引用的 ID
例如:
<defs>
<circle id="circle-1" fill="#000" cx="60" cy="60" r="60"></circle>
</defs>
<mask id="mask-2" fill="white">
<use xlink:href="#circle-1" />
</mask>
<rect id="rect-3" fill="red" width="100" height="100" mask="url(#mask-2)"/>
优化后将变为:(rect-3 这个 id 没有被引用,所以被移除了,另外 2 个 id 被缩短)
<defs>
<circle id="a" fill="#000" cx="60" cy="60" r="60"></circle>
</defs>
<mask id="b" fill="white">
<use xlink:href="#a" />
</mask>
<rect fill="red" width="100" height="100" mask="url(#b)"/>
- 默认开关:开
- 说明:
- 缩短 style 属性
- 深度分析 style 属性继承链,移除无可应用对象的属性
- 如果不存在 style 标签,则根据情况进行 style 和属性的互转
- 配置参数1
- 默认值:false
- 无视 style 标签是否存在,强制执行 style 和属性的互转
- 警告:svg 的样式覆盖规则是 style 属性 > style 标签 > 属性,所以这个规则可能导致不正确的覆盖!
例如:
<rect fill="red" style="fill:blue;background:red;"/>
优化后将变为:(fill 属性将被 style 中的同名定义覆盖,所以被移除了,background 不是标准的 svg 样式,所以也被移除了)
<rect style="fill:blue;"/>
如果 svg 中不存在 style 标签,或配置参数1被设定为 true ,则优化结果为:
<rect fill="blue"/>
- 默认开关:开
- 说明:
- 缩短 style 标签的内容
- 移除重复的定义
- 移除不在SVG规范内的样式
- 配置参数1
- 默认值:true
- 深度分析和优化 style
- 移除无效的选择器
- 合并多个相同的选择器
- 合并多个相同的规则
下面列出的是本工具在配置选项之外的优化工作
- 移除标签间的空白
- 移除 OtherSect 和 OtherDecl 类型的节点(参见本文档下面的 NodeType 说明)
- 无内容的标签自闭合
- 合并所有的 style 标签
- 合并所有的 script 标签
- 合并相邻的文本类型节点或 CDATA 节点
- 合并所有冗余的空白字符
- 从不含文本内容的节点下移除文本子节点
- 如果 CDATA 节点内不包含“<”,则转为普通文本节点
- 支持 W3C 的 SVG2 标准
- 丰富而强大的功能,足够个性化的配置参数
- 追求极致的优化效果
在项目里附带了一个 XML 解析工具,安装项目后即可直接使用,无需额外安装。
const xmlParser = require('svg-slimming/xml-parser.js');
xmlParser.parse(xmlcode).then(result => {
console.log(result);
});
console.log(xmlParser.NodeType);
其中 xmlcode 为字符串格式的 xml 文本(不限于svg)
节点类型尽可能遵循 DOM 规范的定义 参考文档
具体定义如下:
-
元素节点 | Tag
- value:1
- nodeName:<tagName>
- 包含 attributes 属性和 childNodes 属性
-
文本节点 | Text
- value:3
- nodeName:#text
- 包含 textContent 属性
-
CDATA
- value:4
- nodeName:#cdata
- 包含 textContent 属性
-
OtherSect
- value:5
- nodeName:#<sectName>
- 包含 textContent 属性
- 指除了 CDATA 之外的其它区块,如 <![INCLUDE[...]]>
-
OtherDecl
- value:6
- nodeName:#<declName>
- 包含 textContent 属性
- 指除了 DocType 之外的其它声明,如
-
xml声明 | XMLDecl
- value:7
- nodeName:#xml-decl
- 包含 textContent 属性
-
注释 | Comments
- value:8
- nodeName:#comments
- 包含 textContent 属性
-
document节点 | Document
- value:9
- nodeName:#document
- 包含 childNodes 属性
- 为 xml-parser 解析后输出的根节点对象
-
DocType
- value:10
- nodeName:#doctype
- 包含 textContent 属性
interface INode {
nodeName: string; // 节点名称
nodeType: NodeType; // 节点类型
namespace?: string; // 命名空间(如果有)
textContent?: string; // 文本内容(如果有)
readonly attributes?: IAttr[]; // 属性列表(如果有)
readonly childNodes?: INode[]; // 子节点(如果有)
parentNode?: INode; // 父节点
cloneNode(): INode;
appendChild(childNode: INode): void; // 插入子节点
insertBefore(childNode: INode, previousTarget: INode): void; // 在某个指定的子节点之前插入子节点
replaceChild(childNode: INode, ...children: INode[]): void; // 替换某个子节点
removeChild(childNode: INode): void; // 移除某个子节点
hasAttribute(name: string, namespace?: string): boolean;
getAttribute(name: string, namespace?: string): string; // 获取某个属性的值
setAttribute(name: string, value: string, namespace?: string): void; // 设置某个属性的值
removeAttribute(name: string, namespace?: string): void; // 移除某个属性
}
interface INode {
name: string; // 属性名称(不含命名空间)
value: string; // 值
fullname: string; // 属性完整名称(含命名空间)
namespace?: string; // 属性命名空间
}
- 严格遵循 xml 规范,遇到不符合规范的 xml 文本会报错,而不是尝试修复
- 支持解析 xml 声明、doctype、注释、CDATA等类型的节点
- 会正确解析 xml 的命名空间
- 会正确解析元素节点的属性,包括含命名空间的属性
- 严格反映原始文档的内容顺序和格式,不会做文本节点合并等额外的事