图片来源:pixiv 38190692
SVG 图标是矢量图,能够很方便的转换颜色,修改文字,画质无损进行缩放,并且文件很是小,相比一样的 png 图片,大小仅为一成
SVG 经过可配置颜色和配置文字的方式,有效减小了图标文件的个数。从而使设计师和前端工程师工做量都减小,还能提高了加载速度javascript
更新于 2018.7.29
首发于夏味的博客: xiaweiss.comphp
说到性能优化,常见的一种方式就是压缩图片,一般图片最多压缩到原文件的 50%。并且若是一个图标有 7 种颜色呢?那么设计就得给出 7 种颜色的图片,前端代码也得引用不一样的 7 个路径。。。想一想都以为复杂。css
SVG 图完美地解决了这一痛点,大小仅为原文件 10% 左右。还能够经过改写代码来任意改变颜色,甚至支持在代码中动态地传入颜色。动态地传入颜色时,即使有 1万种颜色,也仅仅一个文件。html
而生成 SVG 文件也很是简单,设计师可使用 矢量图 绘图软件直接导出 svg 格式的文件,如 Adobe Illustrator(简称 AI)、sketch前端
固然对于 Adobe Photoshop 中绘制的图片,手工转换矢量图比较困难耗时,在线工具解决了这一难题java
其中目前免费在线转换工具里,这款是最好的 https://www.vectorizer.io/node
转换后,可能会有一些冗余的代码,可使用命令行工具 svgo 进行批量压缩。固然若是文件数量很少,直接使用在线工具 https://jakearchibald.github.io/svgomg/ 便可。react
这些个 SVG 压缩工具只是静态工具,不会被上传到网络上去,不须要担忧被盗图,有兴趣的同窗能够研究下源码,以及那个web 压缩工具的源码css3
首先 svg 在浏览器里和手机上,与图片同样的,能够正常显示出来 下面这个就是一个完整的 SVG 图,包括文字git
下面将它改写为为 400px 宽度的 SVG 图,仍然能够看到很清晰
接下来,使用微信屏幕截图,看看一样 400px 宽度的 png 图,而且使用智图 压缩图片
接下来看看这三个文件的大小
能够看出 SVG 图能够任意改变尺寸,不损失清晰度 相比 png 图体积小不少的状况下,仍然比 png 图更清晰
接下来使用代码编辑器打开 SVG 文件,能够看到以下代码
也许看到这一堆代码要头晕了。别担忧,实际应用时,并不须要本身手写 SVG 代码,只是改改就足够了 仔细看很相似前端经常使用的 html 标签
<?xml version="1.0" encoding="UTF-8"?>
<svg width="60px" height="24px" viewBox="0 0 60 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 51 (57462) - http://www.bohemiancoding.com/sketch -->
<title>按钮/关注-红色底</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="按钮/关注-红色底" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<rect id="Rectangle-3" fill="#FF4C6A" x="0" y="0" width="60" height="24" rx="12"></rect>
<g id="icon/关注加号" transform="translate(3.000000, 0.000000)">
<g id="Group" stroke-width="1" transform="translate(8.000000, 8.000000)" fill="#FFFFFF">
<path d="M3,3 L3,1 C3,0.44771525 3.44771525,1.01453063e-16 4,0 C4.55228475,-1.01453063e-16 5,0.44771525 5,1 L5,3 L7,3 C7.55228475,3 8,3.44771525 8,4 C8,4.55228475 7.55228475,5 7,5 L5,5 L5,7 C5,7.55228475 4.55228475,8 4,8 C3.44771525,8 3,7.55228475 3,7 L3,5 L1,5 C0.44771525,5 6.76353751e-17,4.55228475 0,4 C-6.76353751e-17,3.44771525 0.44771525,3 1,3 L3,3 Z" id="Combined-Shape"></path>
</g>
<rect id="Rectangle-10" fill="#D8D8D8" opacity="0" x="0" y="0" width="24" height="24"></rect>
</g>
<text id="哈哈" font-family="PingFangSC-Regular, PingFang SC" font-size="12" font-weight="normal" line-spacing="18" fill="#FFFFFF">
<tspan x="24" y="16">哈哈</tspan>
</text>
</g>
</svg>
复制代码
<svg width="60px" height="24px" viewBox="0 0 60 24" ... > ... </svg>
复制代码
svg 标签来控制宽高,width,height 是实际显示的宽高,能够修改成你想要显示的大小 而 viewBox 里的大小,则是原始大小,能够理解为画纸的大小位置,其中左上角坐标为 0 0,右下角坐标为 60 24(方向分别为 x, y)
<g id="Group" stroke-width="1" transform="translate(8.000000, 8.000000)" fill="#FFFFFF"> ... </g>
复制代码
g 标签表示分组,也就是绘图软件中的图层。相似代码中的继承,它的属性,若是子标签里没有规定,就会使用它的属性设置 例以下面这两段代码是一样的效果
<g fill="#FF4C6A">
<rect x="0" y="0" width="60" height="24" rx="12"></rect>
</g>
复制代码
<g >
<rect fill="#FF4C6A" x="0" y="0" width="60" height="24" rx="12"></rect>
</g>
复制代码
path 表示线条, reat 表示方形,text 表示文字 代码 d="M3,3 L3,1 ...'
是绘制线条的代码,也称做路径(path)
fill 表示填充色,相似于 css 里的背景色(background-color)
stroke 表示描边,相似于 css 的边框颜色(border-color)
因此修改色值时,只须要修改这两个颜色便可 色值与 css 相同,可使用透明色 transparent,以及 rgba(0,0,0,0.5) 也能够添加属性 opacity='0.5'
来控制透明度,值为 0 ~ 1
至于修改文字,找到对应的文字,直接替换便可
因为最近正在作 react-native, SVG 的配置难度较大,就用它来示例一下
这里使用 react-native-svg 库来渲染 SVG 图片
注意设计师导出 SVG 图标前,请清除掉蒙层(mask)、颜色叠加和滤镜(filter)、阴影(shadow),目前 react-native 是不支持的
首先使用 msvgc 库来一键把 SVG 文件转换为 React 组件
nodejs 环境里安装 msvgc,源文件放置到 App/Svg/目录下,配置脚本运行便可 导出的组件位于 ./App/Components/Svg/svg
目录
"scripts": {
"svg": "msvgc --react-native -f ./App/Svg/ -o ./App/Components/Svg && standard --fix './App/Components/Svg/svg/*.js'"
}
复制代码
再把修正属性的语法,所有改成驼峰写法,例如 fill-rule
改成 fillRule
修正后将文件移动到 App/Components/Svg
(其余目录也昆虫,由于每次新转换时,会覆盖App/Components/Svg/svg/
目录)
接下来,进一步修改代码,就能够经过组件的 props 值里动态传参了
import React from 'react'
import Svg, { G, Rect, Path, Text } from 'react-native-svg'
import { path } from 'ramda' // 根据键名取值,取不到或错误时,返回 undefined
// path([键名],被取值的对象)
const ButtonFollow = props => {
const Color = {
red: '#ff4c6a',
grey: '#6c6c6c'
}
const fillColor = path([props.color], Color) || props.color || Color.red
return (
<Svg
width={props.width || 60}
height={props.height || 24}
viewBox='0 0 60 24'>
<G stroke='none' strokeWidth='1' fill='none' fillRule='evenodd'>
<Rect fill={fillColor} x='0' y='0' width='60' height='24' rx='12' />
<G strokeWidth='1' transform='translate(8, 8)' fill='#FFFFFF'>
<Path d='M3,3 L3,1 C3,0.44771525 3.44771525,1.01453063e-16 4,0 C4.55228475,-1.01453063e-16 5,0.44771525 5,1 L5,3 L7,3 C7.55228475,3 8,3.44771525 8,4 C8,4.55228475 7.55228475,5 7,5 L5,5 L5,7 C5,7.55228475 4.55228475,8 4,8 C3.44771525,8 3,7.55228475 3,7 L3,5 L1,5 C0.44771525,5 6.76353751e-17,4.55228475 0,4 C-6.76353751e-17,3.44771525 0.44771525,3 1,3 L3,3 Z' />
</G>
<Text fontSize='12' lineSpacing='18' fill='#FFFFFF' x='24' y='16'>
{props.text || '关注'}
</Text>
</G>
</Svg>
)
}
export default ButtonFollow
复制代码
调用
<ButtonFollow width={300} height={120} color='red' />
<ButtonFollow /> 取默认值 64,24,默认色 red
<ButtonFollow width={300} height={120} color='#ccc' /> 任意颜色
复制代码
(基于 react-naive 0.55.4 介绍)
facebook 自家也出品了一个库 react-art,而且有 react-native-art,两者大致上使用的同一套 API 它支持的元素标签交少,例如没有方形。但更简洁,不须要引入额外库 (react-native-svg 压缩后大约 200KB)
相关语法能够看 react-native-art-绘图入门 了解一下 源码位于 node_modules/react-native/Libraries/ART/ReactNativeART.js
缺点是尚未找到现成的转换插件,须要手工转换
首先来封装一个方形组件,width、height 控制宽高,r 控制圆角半径(border-radius)
import React from 'react'
import { ART } from 'react-native'
const { Shape } = ART
function extractNumber (value, defaultValue) {
if (value == null) {
return defaultValue
}
return +value
}
const RectART = props => {
let w = extractNumber(props.width, 0)
let h = extractNumber(props.height, 0)
let r = extractNumber(props.r, 0)
if (w === 0 || h === 0) return null
if (r > 0) {
h -= r * 2
w -= r * 2
return <Shape {...props}
d={`M${r},0 h${w} a${r},${r} 0 0,1 ${r},${r} v${h} a${r},${r} 0 0,1 ${-r},${r} h${-w} a${r},${r} 0 0,1 ${-r},${-r} v${-h} a${r},${r} 0 0,1 ${r},${-r} z`}
/>
} else {
return <Shape {...props} d={`h${w} v${h} h${-w} z`} />
}
}
export default RectART
复制代码
接下来转换按钮
node_modules/art/core/path.js
)transform = new Transform().scale(2).translate(2, 3)
复制代码
其中 font 指定字体格式(注意必须指定字体) (react-native 里指定多个字体只有第一个字体生效)
font='normal 12 PingFangSC-Regular'
复制代码
也能够写为(注意必须指定字体)
font={fontFamily: 'PingFangSC-Regular',fontSize: '12'}
复制代码
还有两个属性是 fontWeight、fontStyle
import React from 'react'
import { path } from 'ramda' // 根据键名取值,取不到或错误时,返回 undefined
// path([键名],被取值的对象)
import { ART, View } from 'react-native'
import Rect from './RectART.js'
const { Group, Shape, Surface, Transform, Text } = ART
const ButtonFollow = props => {
const Color = {
red: '#ff4c6a',
grey: '#6c6c6c'
}
const fillColor = path([props.color], Color) || props.color || Color.red
const X = (Math.min(props.width / 60, props.height / 24)) || 1
return (
<View style={props.style}>
<Surface width={props.width || 60} height={props.height || 24} >
<Group scale={X} >
<Rect fill={fillColor} r='12' width='60' height='24' />
<Shape fill='#FFFFFF' transform={new Transform().translate(8, 8)} d='M3,3 L3,1 C3,0.44771525 3.44771525,1.01453063e-16 4,0 C4.55228475,-1.01453063e-16 5,0.44771525 5,1 L5,3 L7,3 C7.55228475,3 8,3.44771525 8,4 C8,4.55228475 7.55228475,5 7,5 L5,5 L5,7 C5,7.55228475 4.55228475,8 4,8 C3.44771525,8 3,7.55228475 3,7 L3,5 L1,5 C0.44771525,5 6.76353751e-17,4.55228475 0,4 C-6.76353751e-17,3.44771525 0.44771525,3 1,3 L3,3 Z' />
<Text font={'normal 12 PingFangSC-Regular'} fill='#FFF' transform={new Transform().translate(24, 4)}>
{props.text || '关注'}
</Text>
</Group>
</Surface>
</View>
)
}
export default ButtonFollow
复制代码
<ButtonFollow width={300} height={120} />
复制代码
(基于 react-naive 0.55.4 介绍) 下面是我看了源码以后罗列的 API,供参考使用
相关语法能够看 react-native-art-绘图入门 了解一下 源码位于 node_modules/react-native/Libraries/ART/ReactNativeART.js
Property | Type | Description |
---|---|---|
width | string | |
heigh | string | - |
Property | Type | Description |
---|---|---|
opacity | number | |
scale | number | |
scaleX | number | |
scaleY | number | |
transform | transform | |
visible | boolean | false equals opacity 0 |
Property | Type | Description |
---|---|---|
d | path | |
fill | string | Color |
opacity | number | |
scale | number | |
scaleX | number | |
scaleY | number | |
strokeCap | string | butt, square, round(default) |
strokeDash | ||
strokeJoin | string | miter, bevel, round |
strokeWidth | number | 1(default) |
transform | transform | |
visible | boolean | false equals opacity 0 |
Property | Type | Description |
---|---|---|
alignment | string | right, center, left(default) |
fill | string | Color |
font | string | normal 10 PingFangSC-Regular |
font | object | {fontFamily,fontSize,fontWeight,fontStyle} |
opacity | number | |
path | path | |
scale | number | |
scale | number | |
scaleX | number | |
scaleX | number | |
scaleY | number | |
scaleY | number | |
strokeCap | string | butt, square, round(default) |
strokeDash | ||
strokeJoin | string | miter, bevel, round |
strokeWidth | number | 1(default) |
transform | transform | - |
Property | params | Description |
---|---|---|
transform | xx, yx, xy, yy, x, y | |
translate | x, y | |
move | x, y | |
moveTo | x, y | |
scale | x, y | |
scaleTo | x, y | |
rotate | deg, x, y | |
rotateTo | deg, x, y | |
resizeTo | width, height | this.scaleTo(width / w, height / h) |
point | x, y | |
inversePoint | x, y | - |
上面表格含 To 的都是绝对坐标,例如 move 是相对坐标,moveTo 是绝对坐标
其余存在但不经常使用的 API Path ClippingRectangle LinearGradient Pattern RadialGradient
具体能够看 w3c 官方文档 https://www.w3.org/TR/SVG2/paths.html 大写字母都表明绝对坐标 小写字母都表明相对坐标
下面这几个写法效果相同 M 10 20 M 15 25 v 5 M 10,20 M 15,25 v 5 M10,20 M15,25 v5 M10,20 15,25 v5 (与前一个字母相同时,字母能够省略)
字母主要有如下几种,能够对应到上面的表格
Command | Name | Parameters | Description |
---|---|---|---|
M | moveto | x, y | 移动 |
L | lineto | x, y | 画线 |
H | horizontal lineto | x | 画水平线 |
V | vertical lineto | y | 画垂直线 |
A | elliptical arc | 椭圆 | |
Z | closepath | 链接到起始点,只能在最后使用 |
椭圆 A 有6个参数 rx ry x-axis-rotation large-arc-flag sweep-flag x y 含义分别为
Parameters | Description |
---|---|
rx | x 轴半径 |
ry | y 轴半径 |
x-axis-rotation | 相对于 x 轴的旋转角度,例如 30 表示 30 度 |
large-arc-flag | 1 绘制大圆,0 绘制小圆 |
sweep-flag | 旋转方式: 1 顺时针,0 逆时针 |
x | 结束点的 x 坐标 |
y | 结束点的 x 坐标 |