圖片來源: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 座標 |